Skip to content

Commit a4afd77

Browse files
committed
Replace package object compiletime by top-level definitions
Also move S from scala.compiletime to scala.compiletime.ops.int where all the other type operators on Int are defined.
1 parent 619fcf1 commit a4afd77

File tree

19 files changed

+377
-28
lines changed

19 files changed

+377
-28
lines changed

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,15 @@ class Definitions {
222222

223223
@tu lazy val ScalaXmlPackageClass: Symbol = getPackageClassIfDefined("scala.xml")
224224

225-
@tu lazy val CompiletimePackageObject: Symbol = requiredModule("scala.compiletime.package")
226-
@tu lazy val Compiletime_codeOf: Symbol = CompiletimePackageObject.requiredMethod("codeOf")
227-
@tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageObject.requiredMethod("erasedValue")
228-
@tu lazy val Compiletime_uninitialized: Symbol = CompiletimePackageObject.requiredMethod("uninitialized")
229-
@tu lazy val Compiletime_error : Symbol = CompiletimePackageObject.requiredMethod(nme.error)
230-
@tu lazy val Compiletime_requireConst : Symbol = CompiletimePackageObject.requiredMethod("requireConst")
231-
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageObject.requiredMethod("constValue")
232-
@tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageObject.requiredMethod("constValueOpt")
233-
@tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageObject.requiredMethod("summonFrom")
225+
@tu lazy val CompiletimePackageClass: Symbol = requiredPackage("scala.compiletime").moduleClass
226+
@tu lazy val Compiletime_codeOf: Symbol = CompiletimePackageClass.requiredMethod("codeOf")
227+
@tu lazy val Compiletime_erasedValue : Symbol = CompiletimePackageClass.requiredMethod("erasedValue")
228+
@tu lazy val Compiletime_uninitialized: Symbol = CompiletimePackageClass.requiredMethod("uninitialized")
229+
@tu lazy val Compiletime_error : Symbol = CompiletimePackageClass.requiredMethod(nme.error)
230+
@tu lazy val Compiletime_requireConst : Symbol = CompiletimePackageClass.requiredMethod("requireConst")
231+
@tu lazy val Compiletime_constValue : Symbol = CompiletimePackageClass.requiredMethod("constValue")
232+
@tu lazy val Compiletime_constValueOpt: Symbol = CompiletimePackageClass.requiredMethod("constValueOpt")
233+
@tu lazy val Compiletime_summonFrom : Symbol = CompiletimePackageClass.requiredMethod("summonFrom")
234234
@tu lazy val CompiletimeTestingPackage: Symbol = requiredPackage("scala.compiletime.testing")
235235
@tu lazy val CompiletimeTesting_typeChecks: Symbol = CompiletimeTestingPackage.requiredMethod("typeChecks")
236236
@tu lazy val CompiletimeTesting_typeCheckErrors: Symbol = CompiletimeTestingPackage.requiredMethod("typeCheckErrors")
@@ -1049,7 +1049,7 @@ class Definitions {
10491049
}
10501050

10511051
final def isCompiletime_S(sym: Symbol)(using Context): Boolean =
1052-
sym.name == tpnme.S && sym.owner == CompiletimePackageObject.moduleClass
1052+
sym.name == tpnme.S && sym.owner == CompiletimeOpsIntModuleClass
10531053

10541054
private val compiletimePackageAnyTypes: Set[Name] = Set(tpnme.Equals, tpnme.NotEquals)
10551055
private val compiletimePackageIntTypes: Set[Name] = Set(

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -4059,9 +4059,9 @@ object Types {
40594059
val owner = tycon.symbol.owner
40604060
val nArgs = args.length
40614061
val constantType =
4062-
if (owner == defn.CompiletimePackageObject.moduleClass) name match {
4063-
case tpnme.S if nArgs == 1 => constantFold1(natValue, _ + 1)
4064-
case _ => None
4062+
if (defn.isCompiletime_S(tycon.symbol)) {
4063+
if (nArgs == 1) constantFold1(natValue, _ + 1)
4064+
else None
40654065
} else if (owner == defn.CompiletimeOpsAnyModuleClass) name match {
40664066
case tpnme.Equals if nArgs == 2 => constantFold2(constValue, _ == _)
40674067
case tpnme.NotEquals if nArgs == 2 => constantFold2(constValue, _ != _)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
package scala.compiletime
2+
package ops
3+
4+
object int:
5+
/** Successor of a natural number where zero is the type 0 and successors are reduced as if the definition was
6+
*
7+
* ```scala
8+
* type S[N <: Int] <: Int = N match {
9+
* case 0 => 1
10+
* case 1 => 2
11+
* case 2 => 3
12+
* ...
13+
* case 2147483646 => 2147483647
14+
* }
15+
* ```
16+
* @syntax markdown
17+
*/
18+
type S[N <: Int] <: Int
19+
20+
/** Addition of two `Int` singleton types.
21+
* ```scala
22+
* val sum: 2 + 2 = 4
23+
* ```
24+
* @syntax markdown
25+
*/
26+
type +[X <: Int, Y <: Int] <: Int
27+
28+
/** Subtraction of two `Int` singleton types.
29+
* ```scala
30+
* val sub: 4 - 2 = 2
31+
* ```
32+
* @syntax markdown
33+
*/
34+
type -[X <: Int, Y <: Int] <: Int
35+
36+
/** Multiplication of two `Int` singleton types.
37+
* ```scala
38+
* val mul: 4 * 2 = 8
39+
* ```
40+
* @syntax markdown
41+
*/
42+
type *[X <: Int, Y <: Int] <: Int
43+
44+
/** Integer division of two `Int` singleton types.
45+
* ```scala
46+
* val div: 5 / 2 = 2
47+
* ```
48+
* @syntax markdown
49+
*/
50+
type /[X <: Int, Y <: Int] <: Int
51+
52+
/** Remainder of the division of `X` by `Y`.
53+
* ```scala
54+
* val mod: 5 % 2 = 1
55+
* ```
56+
* @syntax markdown
57+
*/
58+
type %[X <: Int, Y <: Int] <: Int
59+
60+
/** Binary left shift of `X` by `Y`.
61+
* ```scala
62+
* val lshift: 1 << 2 = 4
63+
* ```
64+
* @syntax markdown
65+
*/
66+
type <<[X <: Int, Y <: Int] <: Int
67+
68+
/** Binary right shift of `X` by `Y`.
69+
* ```scala
70+
* val rshift: 10 >> 1 = 5
71+
* ```
72+
* @syntax markdown
73+
*/
74+
type >>[X <: Int, Y <: Int] <: Int
75+
76+
/** Binary right shift of `X` by `Y`, filling the left with zeros.
77+
* ```scala
78+
* val rshiftzero: 10 >>> 1 = 5
79+
* ```
80+
* @syntax markdown
81+
*/
82+
type >>>[X <: Int, Y <: Int] <: Int
83+
84+
/** Bitwise xor of `X` and `Y`.
85+
* ```scala
86+
* val xor: 10 ^ 30 = 20
87+
* ```
88+
* @syntax markdown
89+
*/
90+
type ^[X <: Int, Y <: Int] <: Int
91+
92+
/** Less-than comparison of two `Int` singleton types.
93+
* ```scala
94+
* val lt1: 4 < 2 = false
95+
* val lt2: 2 < 4 = true
96+
* ```
97+
* @syntax markdown
98+
*/
99+
type <[X <: Int, Y <: Int] <: Boolean
100+
101+
/** Greater-than comparison of two `Int` singleton types.
102+
* ```scala
103+
* val gt1: 4 > 2 = true
104+
* val gt2: 2 > 2 = false
105+
* ```
106+
* @syntax markdown
107+
*/
108+
type >[X <: Int, Y <: Int] <: Boolean
109+
110+
/** Greater-or-equal comparison of two `Int` singleton types.
111+
* ```scala
112+
* val ge1: 4 >= 2 = true
113+
* val ge2: 2 >= 3 = false
114+
* ```
115+
* @syntax markdown
116+
*/
117+
type >=[X <: Int, Y <: Int] <: Boolean
118+
119+
/** Less-or-equal comparison of two `Int` singleton types.
120+
* ```scala
121+
* val lt1: 4 <= 2 = false
122+
* val lt2: 2 <= 2 = true
123+
* ```
124+
* @syntax markdown
125+
*/
126+
type <=[X <: Int, Y <: Int] <: Boolean
127+
128+
/** Bitwise and of `X` and `Y`.
129+
* ```scala
130+
* val and1: BitwiseAnd[4, 4] = 4
131+
* val and2: BitwiseAnd[10, 5] = 0
132+
* ```
133+
* @syntax markdown
134+
*/
135+
type BitwiseAnd[X <: Int, Y <: Int] <: Int
136+
137+
/** Bitwise or of `X` and `Y`.
138+
* ```scala
139+
* val or: BitwiseOr[10, 11] = 11
140+
* ```
141+
* @syntax markdown
142+
*/
143+
type BitwiseOr[X <: Int, Y <: Int] <: Int
144+
145+
/** Absolute value of an `Int` singleton type.
146+
* ```scala
147+
* val abs: Abs[-1] = 1
148+
* ```
149+
* @syntax markdown
150+
*/
151+
type Abs[X <: Int] <: Int
152+
153+
/** Negation of an `Int` singleton type.
154+
* ```scala
155+
* val neg1: Neg[-1] = 1
156+
* val neg2: Neg[1] = -1
157+
* ```
158+
* @syntax markdown
159+
*/
160+
type Negate[X <: Int] <: Int
161+
162+
/** Minimum of two `Int` singleton types.
163+
* ```scala
164+
* val min: Min[-1, 1] = -1
165+
* ```
166+
* @syntax markdown
167+
*/
168+
type Min[X <: Int, Y <: Int] <: Int
169+
170+
/** Maximum of two `Int` singleton types.
171+
* ```scala
172+
* val max: Max[-1, 1] = 1
173+
* ```
174+
* @syntax markdown
175+
*/
176+
type Max[X <: Int, Y <: Int] <: Int
177+
178+
/** String conversion of an `Int` singleton type.
179+
* ```scala
180+
* val abs: ToString[1] = "1"
181+
* ```
182+
* @syntax markdown
183+
*/
184+
type ToString[X <: Int] <: String
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package scala
2+
package compiletime
3+
4+
import annotation.compileTimeOnly
5+
6+
/** Use this method when you have a type, do not have a value for it but want to
7+
* pattern match on it. For example, given a type `Tup <: Tuple`, one can
8+
* pattern-match on it as follows:
9+
* ```scala
10+
* inline erasedValue[Tup] match {
11+
* case _: EmptyTuple => ...
12+
* case _: h *: t => ...
13+
* }
14+
* ```
15+
* This value can only be used in an inline match and the value cannot be used in
16+
* the branches.
17+
* @syntax markdown
18+
*/
19+
erased def erasedValue[T]: T = ???
20+
21+
/** Used as the initializer of a mutable class or object field, like this:
22+
*
23+
* var x: T = uninitialized
24+
*
25+
* This signifies that the field is not initialized on its own. It is still initialized
26+
* as part of the bulk initialization of the object it belongs to, which assigns zero
27+
* values such as `null`, `0`, `0.0`, `false` to all object fields.
28+
*/
29+
@compileTimeOnly("`uninitialized` can only be used as the right hand side of a mutable field definition")
30+
def uninitialized: Nothing = ???
31+
32+
/** The error method is used to produce user-defined compile errors during inline expansion.
33+
* If an inline expansion results in a call error(msgStr) the compiler produces an error message containing the given msgStr.
34+
*
35+
* ```scala
36+
* error("My error message")
37+
* ```
38+
* or
39+
* ```scala
40+
* inline def errorOnThisCode(inline x: Any) =
41+
* error("My error of this code: " + codeOf(x))
42+
* ```
43+
* @syntax markdown
44+
*/
45+
inline def error(inline msg: String): Nothing = ???
46+
47+
/** Returns the string representation of argument code:
48+
*
49+
* ```scala
50+
* inline def logged(inline p1: Any) =
51+
* ("code: " + codeOf(p1), p1)
52+
*
53+
* logged(identity("foo"))
54+
* // above is equivalent to:
55+
* // ("code: scala.Predef.identity("foo")", identity("foo"))
56+
* ```
57+
*
58+
* The formatting of the code is not stable across version of the compiler.
59+
*
60+
* @note only `inline` arguments will be displayed as "code".
61+
* Other values may display unintutively.
62+
*
63+
* @syntax markdown
64+
*/
65+
transparent inline def codeOf(arg: Any): String =
66+
// implemented in dotty.tools.dotc.typer.Inliner.Intrinsics
67+
error("Compiler bug: `codeOf` was not evaluated by the compiler")
68+
69+
/** Checks at compiletime that the provided values is a constant after
70+
* inlining and constant folding.
71+
*
72+
* Usage:
73+
* ```scala
74+
* inline def twice(inline n: Int): Int =
75+
* requireConst(n) // compile-time assertion that the parameter `n` is a constant
76+
* n + n
77+
*
78+
* twice(1)
79+
* val m: Int = ...
80+
* twice(m) // error: expected a constant value but found: m
81+
* ```
82+
* @syntax markdown
83+
*/
84+
inline def requireConst(inline x: Boolean | Byte | Short | Int | Long | Float | Double | Char | String): Unit =
85+
// implemented in dotty.tools.dotc.typer.Inliner
86+
error("Compiler bug: `requireConst` was not evaluated by the compiler")
87+
88+
/** Same as `constValue` but returns a `None` if a constant value
89+
* cannot be constructed from the provided type. Otherwise returns
90+
* that value wrapped in `Some`.
91+
*/
92+
transparent inline def constValueOpt[T]: Option[T] =
93+
// implemented in dotty.tools.dotc.typer.Inliner
94+
error("Compiler bug: `constValueOpt` was not evaluated by the compiler")
95+
96+
/** Given a constant, singleton type `T`, convert it to a value
97+
* of the same singleton type. For example: `assert(constValue[1] == 1)`.
98+
*/
99+
transparent inline def constValue[T]: T =
100+
// implemented in dotty.tools.dotc.typer.Inliner
101+
error("Compiler bug: `constValue` was not evaluated by the compiler")
102+
103+
/** Given a tuple type `(X1, ..., Xn)`, returns a tuple value
104+
* `(constValue[X1], ..., constValue[Xn])`.
105+
*/
106+
inline def constValueTuple[T <: Tuple]: T =
107+
val res =
108+
inline erasedValue[T] match
109+
case _: EmptyTuple => EmptyTuple
110+
case _: (t *: ts) => constValue[t] *: constValueTuple[ts]
111+
end match
112+
res.asInstanceOf[T]
113+
end constValueTuple
114+
115+
/** Summons first given matching one of the listed cases. E.g. in
116+
*
117+
* ```scala
118+
* given B { ... }
119+
*
120+
* summonFrom {
121+
* case given A => 1
122+
* case given B => 2
123+
* case given C => 3
124+
* case _ => 4
125+
* }
126+
* ```
127+
* the returned value would be `2`.
128+
* @syntax markdown
129+
*/
130+
transparent inline def summonFrom[T](f: Nothing => T): T =
131+
error("Compiler bug: `summonFrom` was not evaluated by the compiler")
132+
133+
/** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
134+
* The summoning is delayed until the call has been fully inlined.
135+
*
136+
* @tparam T the type of the value to be summoned
137+
* @return the given value typed as the provided type parameter
138+
*/
139+
transparent inline def summonInline[T]: T = summonFrom {
140+
case t: T => t
141+
}
142+
143+
/** Given a tuple T, summons each of its member types and returns them in
144+
* a Tuple.
145+
*
146+
* @tparam T the tuple containing the types of the values to be summoned
147+
* @return the given values typed as elements of the tuple
148+
*/
149+
inline def summonAll[T <: Tuple]: T =
150+
val res =
151+
inline erasedValue[T] match
152+
case _: EmptyTuple => EmptyTuple
153+
case _: (t *: ts) => summonInline[t] *: summonAll[ts]
154+
end match
155+
res.asInstanceOf[T]
156+
end summonAll
157+
158+
/** Assertion that an argument is by-name. Used for nullability checking. */
159+
def byName[T](x: => T): T = x

0 commit comments

Comments
 (0)