Skip to content

Commit 04ee39b

Browse files
committed
Add constValue function
A function that produces the constant value represented by a type. Also: support _(_), _.head, _.tail on arbitrary tuples.
1 parent 825db1b commit 04ee39b

File tree

6 files changed

+112
-89
lines changed

6 files changed

+112
-89
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ class Definitions {
222222
lazy val TypelevelPackageObject = TypelevelPackageObjectRef.symbol.moduleClass
223223
lazy val Typelevel_errorR = TypelevelPackageObjectRef.symbol.requiredMethodRef(nme.error)
224224
def Typelevel_error(implicit ctx: Context) = Typelevel_errorR.symbol
225+
lazy val Typelevel_constValueR = TypelevelPackageObjectRef.symbol.requiredMethodRef("constValue")
226+
def Typelevel_constValue(implicit ctx: Context) = Typelevel_constValueR.symbol
225227

226228
/** The `scalaShadowing` package is used to safely modify classes and
227229
* objects in scala so that they can be used from dotty. They will

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

+9-3
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
887887
false
888888
}
889889

890-
/** Compare `tp` of form `S[arg]` with `other`, via ">:>` if fromBelowis true, "<:<" otherwise.
890+
/** Compare `tp` of form `S[arg]` with `other`, via ">:>` if fromBelow is true, "<:<" otherwise.
891891
* If `arg` is a Nat constant `n`, proceed with comparing `n + 1` and `other`.
892892
* Otherwise, if `other` is a Nat constant `n`, proceed with comparing `arg` and `n - 1`.
893893
*/
@@ -951,11 +951,17 @@ class TypeComparer(initctx: Context) extends ConstraintHandling {
951951
}
952952

953953
/** Optionally, the `n` such that `tp <:< ConstantType(Constant(n: Int))` */
954-
def natValue(tp: Type): Option[Int] = {
954+
def natValue(tp: Type): Option[Int] = constValue(tp) match {
955+
case Some(Constant(n: Int)) if n >= 0 => Some(n)
956+
case _ => None
957+
}
958+
959+
/** Optionally, the constant `c` such that `tp <:< ConstantType(c)` */
960+
def constValue(tp: Type): Option[Constant] = {
955961
val ct = new AnyConstantType
956962
if (isSubTypeWhenFrozen(tp, ct))
957963
ct.tpe match {
958-
case ConstantType(Constant(n: Int)) if n >= 0 => Some(n)
964+
case ConstantType(c) => Some(c)
959965
case _ => None
960966
}
961967
else None

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,15 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
350350
}
351351

352352
/** The Inlined node representing the inlined call */
353-
def inlined(pt: Type) = {
353+
def inlined(pt: Type): Tree = {
354+
355+
if (inlinedMethod == defn.Typelevel_constValue && callTypeArgs.length == 1) {
356+
ctx.typeComparer.constValue(callTypeArgs.head.tpe) match {
357+
case Some(c) => return tpd.Literal(c).withPos(call.pos)
358+
case _ => ctx.error(i"not a constant type: ${callTypeArgs.head}; cannot take constValue")
359+
}
360+
}
361+
354362
// Compute bindings for all parameters, appending them to bindingsBuf
355363
computeParamBindings(inlinedMethod.info, callTypeArgs, callValueArgss)
356364

library/src-scala3/scala/Tuple.scala

+84-85
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,89 @@ sealed trait Tuple extends Any {
8585

8686
rewrite def genericConcat[T <: Tuple](xs: Tuple, ys: Tuple): Tuple =
8787
fromArray[T](xs.toArray ++ ys.toArray)
88+
89+
rewrite def head: Any = {
90+
erased val resTpe = Typed(_head(this))
91+
val resVal = rewrite _size(this) match {
92+
case 1 =>
93+
val t = asInstanceOf[Tuple1[_]]
94+
t._1
95+
case 2 =>
96+
val t = asInstanceOf[Tuple2[_, _]]
97+
t._1
98+
case 3 =>
99+
val t = asInstanceOf[Tuple3[_, _, _]]
100+
t._1
101+
case 4 =>
102+
val t = asInstanceOf[Tuple4[_, _, _, _]]
103+
t._1
104+
case n if n > 4 && n <= $MaxSpecialized =>
105+
asInstanceOf[Product].productElement(0)
106+
case n if n > $MaxSpecialized =>
107+
val t = asInstanceOf[TupleXXL]
108+
t.elems(0)
109+
}
110+
resVal.asInstanceOf[resTpe.Type]
111+
}
112+
113+
rewrite def tail: Tuple = {
114+
erased val resTpe = Typed(_tail(this))
115+
rewrite _size(this) match {
116+
case 1 =>
117+
()
118+
case 2 =>
119+
val t = asInstanceOf[Tuple2[_, _]]
120+
Tuple1(t._2).asInstanceOf[resTpe.Type]
121+
case 3 =>
122+
val t = asInstanceOf[Tuple3[_, _, _]]
123+
Tuple2(t._2, t._3).asInstanceOf[resTpe.Type]
124+
case 4 =>
125+
val t = asInstanceOf[Tuple4[_, _, _, _]]
126+
Tuple3(t._2, t._3, t._4).asInstanceOf[resTpe.Type]
127+
case 5 =>
128+
val t = asInstanceOf[Tuple5[_, _, _, _, _]]
129+
Tuple4(t._2, t._3, t._4, t._5).asInstanceOf[resTpe.Type]
130+
case n if n > 5 =>
131+
fromArray[resTpe.Type](toArray.tail)
132+
}
133+
}
134+
135+
rewrite def apply(n: Int): Any = {
136+
erased val resTpe = Typed(_index(this, n))
137+
type Result = resTpe.Type
138+
rewrite _size(this) match {
139+
case 1 =>
140+
val t = asInstanceOf[Tuple1[_]]
141+
rewrite n match {
142+
case 0 => t._1.asInstanceOf[Result]
143+
}
144+
case 2 =>
145+
val t = asInstanceOf[Tuple2[_, _]]
146+
rewrite n match {
147+
case 0 => t._1.asInstanceOf[Result]
148+
case 1 => t._2.asInstanceOf[Result]
149+
}
150+
case 3 =>
151+
val t = asInstanceOf[Tuple3[_, _, _]]
152+
rewrite n match {
153+
case 0 => t._1.asInstanceOf[Result]
154+
case 1 => t._2.asInstanceOf[Result]
155+
case 2 => t._3.asInstanceOf[Result]
156+
}
157+
case 4 =>
158+
val t = asInstanceOf[Tuple4[_, _, _, _]]
159+
rewrite n match {
160+
case 0 => t._1.asInstanceOf[Result]
161+
case 1 => t._2.asInstanceOf[Result]
162+
case 2 => t._3.asInstanceOf[Result]
163+
case 3 => t._4.asInstanceOf[Result]
164+
}
165+
case s if s > 4 && s <= $MaxSpecialized && n >= 0 && n < s =>
166+
asInstanceOf[Product].productElement(n).asInstanceOf[Result]
167+
case s if s > $MaxSpecialized && n >= 0 && n < s =>
168+
asInstanceOf[TupleXXL].elems(n).asInstanceOf[Result]
169+
}
170+
}
88171
}
89172

90173
object Tuple {
@@ -167,91 +250,7 @@ object Tuple {
167250
}
168251

169252
@showAsInfix
170-
sealed class *:[+H, +T <: Tuple] extends Tuple {
171-
import Tuple._
172-
173-
rewrite def head: Any = {
174-
erased val resTpe = Typed(_head(this))
175-
val resVal = rewrite _size(this) match {
176-
case 1 =>
177-
val t = asInstanceOf[Tuple1[_]]
178-
t._1
179-
case 2 =>
180-
val t = asInstanceOf[Tuple2[_, _]]
181-
t._1
182-
case 3 =>
183-
val t = asInstanceOf[Tuple3[_, _, _]]
184-
t._1
185-
case 4 =>
186-
val t = asInstanceOf[Tuple4[_, _, _, _]]
187-
t._1
188-
case n if n > 4 && n <= $MaxSpecialized =>
189-
asInstanceOf[Product].productElement(0)
190-
case n if n > $MaxSpecialized =>
191-
val t = asInstanceOf[TupleXXL]
192-
t.elems(0)
193-
}
194-
resVal.asInstanceOf[resTpe.Type]
195-
}
196-
197-
rewrite def tail: Tuple = {
198-
erased val resTpe = Typed(_tail(this))
199-
rewrite _size(this) match {
200-
case 1 =>
201-
()
202-
case 2 =>
203-
val t = asInstanceOf[Tuple2[_, _]]
204-
Tuple1(t._2).asInstanceOf[resTpe.Type]
205-
case 3 =>
206-
val t = asInstanceOf[Tuple3[_, _, _]]
207-
Tuple2(t._2, t._3).asInstanceOf[resTpe.Type]
208-
case 4 =>
209-
val t = asInstanceOf[Tuple4[_, _, _, _]]
210-
Tuple3(t._2, t._3, t._4).asInstanceOf[resTpe.Type]
211-
case 5 =>
212-
val t = asInstanceOf[Tuple5[_, _, _, _, _]]
213-
Tuple4(t._2, t._3, t._4, t._5).asInstanceOf[resTpe.Type]
214-
case n if n > 5 =>
215-
fromArray[resTpe.Type](toArray.tail)
216-
}
217-
}
218-
219-
rewrite def apply(n: Int): Any = {
220-
erased val resTpe = Typed(_index(this, n))
221-
rewrite _size(this) match {
222-
case 1 =>
223-
val t = asInstanceOf[Tuple1[_]]
224-
rewrite n match {
225-
case 0 => t._1.asInstanceOf[resTpe.Type]
226-
}
227-
case 2 =>
228-
val t = asInstanceOf[Tuple2[_, _]]
229-
rewrite n match {
230-
case 0 => t._1.asInstanceOf[resTpe.Type]
231-
case 1 => t._2.asInstanceOf[resTpe.Type]
232-
}
233-
case 3 =>
234-
val t = asInstanceOf[Tuple3[_, _, _]]
235-
rewrite n match {
236-
case 0 => t._1.asInstanceOf[resTpe.Type]
237-
case 1 => t._2.asInstanceOf[resTpe.Type]
238-
case 2 => t._3.asInstanceOf[resTpe.Type]
239-
}
240-
case 4 =>
241-
val t = asInstanceOf[Tuple4[_, _, _, _]]
242-
rewrite n match {
243-
case 0 => t._1.asInstanceOf[resTpe.Type]
244-
case 1 => t._2.asInstanceOf[resTpe.Type]
245-
case 2 => t._3.asInstanceOf[resTpe.Type]
246-
case 3 => t._4.asInstanceOf[resTpe.Type]
247-
}
248-
case s if s > 4 && s <= $MaxSpecialized && n >= 0 && n < s =>
249-
asInstanceOf[Product].productElement(n).asInstanceOf[resTpe.Type]
250-
case s if s > $MaxSpecialized && n >= 0 && n < s =>
251-
asInstanceOf[TupleXXL].elems(n).asInstanceOf[resTpe.Type]
252-
}
253-
}
254-
}
253+
sealed class *:[+H, +T <: Tuple] extends Tuple
255254

256255
object *: {
257256
rewrite def unapply[H, T <: Tuple](x: H *: T) = (x.head, x.tail)

library/src-scala3/scala/typelevel/package.scala

+2
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ package object typelevel {
88

99
rewrite def error(transparent msg: String): Nothing = ???
1010

11+
rewrite def constValue[T]: T = ???
12+
1113
type S[X <: Int] <: Int
1214
}

tests/pos/matchtype.scala

+6
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,10 @@ object Test {
6464
checkSame[Concat[Unit, (String, Int)], (String, Int)]
6565
checkSame[Concat[(Boolean, Boolean), (String, Int)], Boolean *: Boolean *: (String, Int)]
6666
checkSub[(Boolean, Boolean, String, Int), Concat[(Boolean, Boolean), String *: Int *: Unit]]
67+
68+
rewrite def index[Xs <: Tuple](xs: Xs, n: Int): Elem[Xs, n.type] = xs(n).asInstanceOf
69+
70+
val test = (1, "hi", true, 2.0)
71+
index(test, 0): Int
72+
index(test, 1): String
6773
}

0 commit comments

Comments
 (0)