Skip to content

Commit 71e22bb

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 71e22bb

File tree

13 files changed

+370
-24
lines changed

13 files changed

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

0 commit comments

Comments
 (0)