Skip to content

Commit 4e61497

Browse files
committed
Replace EmptyTuple implementation from Unit to Tuple0
1 parent 70963ae commit 4e61497

File tree

64 files changed

+233
-157
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+233
-157
lines changed

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,7 +1337,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
13371337

13381338
/** Creates the nested pairs type tree repesentation of the type trees in `ts` */
13391339
def nestedPairsTypeTree(ts: List[Tree])(implicit ctx: Context): Tree =
1340-
ts.foldRight[Tree](TypeTree(defn.UnitType))((x, acc) => AppliedTypeTree(TypeTree(defn.PairClass.typeRef), x :: acc :: Nil))
1340+
ts.foldRight[Tree](TypeTree(defn.EmptyTupleTypeRef))((x, acc) => AppliedTypeTree(TypeTree(defn.PairClass.typeRef), x :: acc :: Nil))
13411341

13421342
/** Replaces all positions in `tree` with zero-extent positions */
13431343
private def focusPositions(tree: Tree)(implicit ctx: Context): Tree = {

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -745,11 +745,14 @@ class Definitions {
745745
@tu lazy val TupleTypeRef: TypeRef = ctx.requiredClassRef("scala.Tuple")
746746
def TupleClass(implicit ctx: Context): ClassSymbol = TupleTypeRef.symbol.asClass
747747
@tu lazy val Tuple_cons: Symbol = TupleClass.requiredMethod("*:")
748+
@tu lazy val EmptyTupleTypeRef: TypeRef = ctx.requiredClassRef("scala.EmptyTuple")
749+
def EmptyTupleClass(implicit ctx: Context): ClassSymbol = EmptyTupleTypeRef.symbol.asClass
748750
@tu lazy val NonEmptyTupleTypeRef: TypeRef = ctx.requiredClassRef("scala.NonEmptyTuple")
749751
def NonEmptyTupleClass(implicit ctx: Context): ClassSymbol = NonEmptyTupleTypeRef.symbol.asClass
750752
lazy val NonEmptyTuple_tail: Symbol = NonEmptyTupleClass.requiredMethod("tail")
751-
752753
@tu lazy val PairClass: ClassSymbol = ctx.requiredClass("scala.*:")
754+
755+
@tu lazy val Tuple0Module: Symbol = ctx.requiredModule("scala.runtime.Tuple0")
753756
@tu lazy val TupleXXLClass: ClassSymbol = ctx.requiredClass("scala.runtime.TupleXXL")
754757
def TupleXXLModule(implicit ctx: Context): Symbol = TupleXXLClass.companionModule
755758

@@ -1185,7 +1188,7 @@ class Definitions {
11851188
case _ if bound < 0 => Some(acc.reverse)
11861189
case tp: AppliedType if defn.PairClass == tp.classSymbol => rec(tp.args(1), tp.args.head :: acc, bound - 1)
11871190
case tp: AppliedType if defn.isTupleClass(tp.tycon.classSymbol) => Some(acc.reverse ::: tp.args)
1188-
case tp if tp.classSymbol == defn.UnitClass => Some(acc.reverse)
1191+
case tp if tp.classSymbol == defn.EmptyTupleClass => Some(acc.reverse)
11891192
case _ => None
11901193
}
11911194
rec(tp.stripTypeVar, Nil, bound)
@@ -1296,7 +1299,7 @@ class Definitions {
12961299
def syntheticParent(tparams: List[TypeSymbol]): Type =
12971300
if (tparams.isEmpty) TupleTypeRef
12981301
else TypeOps.nestedPairs(tparams.map(_.typeRef))
1299-
if (isTupleClass(cls) || cls == UnitClass) parents :+ syntheticParent(tparams)
1302+
if (isTupleClass(cls) || cls == EmptyTupleClass) parents :+ syntheticParent(tparams)
13001303
else parents
13011304
}
13021305

@@ -1394,6 +1397,7 @@ class Definitions {
13941397
.updated(AnyValClass, ObjectClass)
13951398
.updated(SingletonClass, ObjectClass)
13961399
.updated(TupleClass, ObjectClass)
1400+
.updated(EmptyTupleClass, ObjectClass)
13971401
.updated(NonEmptyTupleClass, ProductClass)
13981402

13991403
// ----- Initialization ---------------------------------------------------

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,6 @@ object TypeOps:
731731
}
732732

733733
def nestedPairs(ts: List[Type])(using Context): Type =
734-
ts.foldRight(defn.UnitType: Type)(defn.PairClass.typeRef.appliedTo(_, _))
734+
ts.foldRight(defn.EmptyTupleTypeRef: Type)(defn.PairClass.typeRef.appliedTo(_, _))
735735

736736
end TypeOps

compiler/src/dotty/tools/dotc/tastyreflect/ReflectionCompilerInterface.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2004,7 +2004,10 @@ class ReflectionCompilerInterface(val rootContext: core.Contexts.Context) extend
20042004
def Definitions_NothingType: Type = defn.NothingType
20052005
def Definitions_NullType: Type = defn.NullType
20062006
def Definitions_StringType: Type = defn.StringType
2007-
2007+
def Definitions_TupleType: Type = defn.TupleTypeRef
2008+
def Definitions_EmptyTupleType: Type = defn.EmptyTupleTypeRef
2009+
def Definitions_NonEmptyTupleType: Type = defn.NonEmptyTupleClass.typeRef
2010+
def Definitions_TupleConsType: Type = defn.PairClass.typeRef
20082011

20092012
///////////////
20102013
// IMPLICITS //

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ class Erasure extends Phase with DenotTransformer {
163163
assert(isErasedType(tp) ||
164164
isAllowed(defn.ArrayClass, "Array.scala") ||
165165
isAllowed(defn.TupleClass, "Tuple.scala") ||
166+
isAllowed(defn.EmptyTupleClass, "Tuple.scala") ||
166167
isAllowed(defn.NonEmptyTupleClass, "Tuple.scala") ||
167168
isAllowed(defn.PairClass, "Tuple.scala"),
168169
i"The type $tp - ${tp.toString} of class ${tp.getClass} of tree $tree : ${tree.tpe} / ${tree.getClass} is illegal after erasure, phase = ${ctx.phase.prev}")

compiler/src/dotty/tools/dotc/transform/TupleOptimizations.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
6969
val size = tpes.size
7070
assert(size > 0)
7171
if (size == 1)
72-
// ()
73-
Literal(Constant(()))
72+
// scala.runtime.Tuple0
73+
ref(defn.Tuple0Module.termRef)
7474
else if (size <= 5)
7575
// val t = tup.asInstanceOf[TupleN[...]]
7676
// TupleN-1(t._2, ..., t._n)
@@ -197,8 +197,8 @@ class TupleOptimizations extends MiniPhase with IdentityDenotTransformer {
197197

198198
private def knownTupleFromIterator(size: Int, it: Tree)(implicit ctx: Context): Tree =
199199
if (size == 0)
200-
// Unit for empty tuple
201-
Literal(Constant(())) // TODO should this code be here? Or assert(size > specializedSize)
200+
// EmptyTuple for empty tuple
201+
ref(defn.EmptyTupleTypeRef) // TODO should this code be here? Or assert(size > specializedSize)
202202
else if (size <= MaxTupleArity) {
203203
// TupleN(it.next(), ..., it.next())
204204

compiler/src/dotty/tools/dotc/transform/TypeUtils.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,25 @@ object TypeUtils {
3131
case ps => ps.reduceLeft(AndType(_, _))
3232
}
3333

34-
/** The arity of this tuple type, which can be made up of Unit, TupleX and `*:` pairs,
34+
/** The arity of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs,
3535
* or -1 if this is not a tuple type.
3636
*/
3737
def tupleArity(implicit ctx: Context): Int = self match {
3838
case AppliedType(tycon, _ :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
3939
val arity = tl.tupleArity
4040
if (arity < 0) arity else arity + 1
4141
case tp1 =>
42-
if (tp1.isRef(defn.UnitClass)) 0
42+
if (tp1.isRef(defn.EmptyTupleClass)) 0
4343
else if (defn.isTupleClass(tp1.classSymbol)) tp1.dealias.argInfos.length
4444
else -1
4545
}
4646

47-
/** The element types of this tuple type, which can be made up of Unit, TupleX and `*:` pairs */
47+
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs */
4848
def tupleElementTypes(implicit ctx: Context): List[Type] = self match {
4949
case AppliedType(tycon, hd :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
5050
hd :: tl.tupleElementTypes
5151
case tp1 =>
52-
if (tp1.isRef(defn.UnitClass)) Nil
52+
if (tp1.isRef(defn.EmptyTupleClass)) Nil
5353
else if (defn.isTupleClass(tp1.classSymbol)) tp1.dealias.argInfos
5454
else throw new AssertionError("not a tuple")
5555
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,9 @@ trait QuotesAndSplices {
411411
}
412412
}
413413

414-
val splicePat = typed(untpd.Tuple(splices.map(x => untpd.TypedSplice(replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
414+
val splicePat =
415+
if splices.isEmpty then ref(defn.Tuple0Module.termRef)
416+
else typed(untpd.Tuple(splices.map(x => untpd.TypedSplice(replaceBindingsInTree.transform(x)))).withSpan(quoted.span), patType)
415417

416418
val unapplySym = if (tree.quoted.isTerm) defn.InternalQuotedExpr_unapply else defn.InternalQuotedType_unapply
417419
val quoteClass = if (tree.quoted.isTerm) defn.QuotedExprClass else defn.QuotedTypeClass

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2274,7 +2274,7 @@ class Typer extends Namer
22742274
else List.fill(arity)(defn.AnyType)
22752275
val elems = tree.trees.lazyZip(pts).map(typed(_, _))
22762276
if (ctx.mode.is(Mode.Type))
2277-
elems.foldRight(TypeTree(defn.UnitType): Tree)((elemTpt, elemTpts) =>
2277+
elems.foldRight(TypeTree(defn.EmptyTupleTypeRef): Tree)((elemTpt, elemTpts) =>
22782278
AppliedTypeTree(TypeTree(defn.PairClass.typeRef), List(elemTpt, elemTpts)))
22792279
.withSpan(tree.span)
22802280
else {

library/src-bootstrapped/scala/Tuple.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,10 @@ object Tuple {
158158
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
159159

160160
/** Empty tuple */
161-
def apply(): EmptyTuple = ()
161+
def apply(): EmptyTuple = scala.runtime.Tuple0.asInstanceOf[EmptyTuple]
162162

163163
/** Matches an empty tuple. */
164-
def unapply(x: Any): Boolean = x.isInstanceOf[EmptyTuple]
164+
def unapply(x: Any): Boolean = x == scala.runtime.Tuple0
165165

166166
/** Convert an array into a tuple of unknown arity and types */
167167
def fromArray[T](xs: Array[T]): Tuple = {
@@ -191,8 +191,8 @@ object Tuple {
191191
Tuple.fromArray(p.productIterator.toArray).asInstanceOf[m.MirroredElemTypes] // TODO use toIArray of Object to avoid double/triple array copy
192192
}
193193

194-
/** Tuple of arity 0 */
195-
type EmptyTuple = Unit
194+
/** Tuple of arity zero */
195+
sealed trait EmptyTuple extends Tuple
196196

197197
/** Tuple of arbitrary non-zero arity */
198198
sealed trait NonEmptyTuple extends Tuple with Product {

library/src-bootstrapped/scala/deriving.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ object deriving {
3434
trait Singleton extends Product {
3535
type MirroredMonoType = this.type
3636
type MirroredType = this.type
37-
type MirroredElemTypes = Unit
38-
type MirroredElemLabels = Unit
37+
type MirroredElemTypes = EmptyTuple
38+
type MirroredElemLabels = EmptyTuple
3939
def fromProduct(p: scala.Product) = this
4040
}
4141

4242
/** A proxy for Scala 2 singletons, which do not inherit `Singleton` directly */
4343
class SingletonProxy(val value: AnyRef) extends Product {
4444
type MirroredMonoType = value.type
4545
type MirroredType = value.type
46-
type MirroredElemTypes = Unit
47-
type MirroredElemLabels = Unit
46+
type MirroredElemTypes = EmptyTuple
47+
type MirroredElemLabels = EmptyTuple
4848
def fromProduct(p: scala.Product) = value
4949
}
5050

library/src/scala/internal/TupledFunction.scala renamed to library/src-bootstrapped/scala/internal/TupledFunction.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import scala.runtime.TupleXXL
66
object TupledFunction {
77

88
def tupledFunction0[F, G]: TupledFunction[F, G] = scala.TupledFunction[F, G](
9-
tupledImpl = (f: F) => ((args: Unit) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G],
10-
untupledImpl = (g: G) => (() => g.asInstanceOf[Unit => Any].apply(())).asInstanceOf[F]
9+
tupledImpl = (f: F) => ((args: EmptyTuple) => f.asInstanceOf[() => Any].apply()).asInstanceOf[G],
10+
untupledImpl = (g: G) => (() => g.asInstanceOf[EmptyTuple => Any].apply(Tuple())).asInstanceOf[F]
1111
)
1212

1313
def tupledFunction1[F, G]: TupledFunction[F, G] = scala.TupledFunction[F, G](

library/src-bootstrapped/scala/quoted/Expr.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Expr[+T] private[scala] {
3838
* ```
3939
*/
4040
final def matches(that: Expr[Any])(using qctx: QuoteContext): Boolean =
41-
!scala.internal.quoted.Expr.unapply[Unit, Unit](this)(using that, false, qctx).isEmpty
41+
!scala.internal.quoted.Expr.unapply[EmptyTuple, EmptyTuple](this)(using that, false, qctx).isEmpty
4242

4343
/** Checked cast to a `quoted.Expr[U]` */
4444
def cast[U](using tp: scala.quoted.Type[U])(using qctx: QuoteContext): scala.quoted.Expr[U] =
@@ -131,7 +131,7 @@ object Expr {
131131
def ofTuple(seq: Seq[Expr[Any]])(using qctx: QuoteContext): Expr[Tuple] = {
132132
seq match {
133133
case Seq() =>
134-
unitExpr
134+
'{ Tuple() }
135135
case Seq('{ $x1: $t1 }) =>
136136
'{ Tuple1($x1) }
137137
case Seq('{ $x1: $t1 }, '{ $x2: $t2 }) =>

library/src-bootstrapped/scala/runtime/Tuple.scala

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ object Tuple {
55
inline val MaxSpecialized = 22
66

77
def toArray(self: Tuple): Array[Object] = (self: Any) match {
8+
case Tuple0 => Array.emptyObjectArray
89
case self: TupleXXL => self.toArray
910
case self: Product => productToArray(self)
10-
case self: Unit => Array.emptyObjectArray
1111
}
1212

1313
def toIArray(self: Tuple): IArray[Object] = (self: Any) match {
14+
case Tuple0 => Array.emptyObjectArray.asInstanceOf[IArray[Object]]
1415
case self: TupleXXL => self.elems
1516
case self: Product => productToArray(self).asInstanceOf[IArray[Object]]
16-
case self: Unit => Array.emptyObjectArray.asInstanceOf[IArray[Object]]
1717
}
1818

1919
def productToArray(self: Product): Array[Object] = {
@@ -27,7 +27,7 @@ object Tuple {
2727
}
2828

2929
def fromArray(xs: Array[Object]): Tuple = xs.length match {
30-
case 0 => ()
30+
case 0 => Tuple0.asInstanceOf[Tuple]
3131
case 1 => Tuple1(xs(0))
3232
case 2 => Tuple2(xs(0), xs(1))
3333
case 3 => Tuple3(xs(0), xs(1), xs(2))
@@ -178,7 +178,7 @@ object Tuple {
178178
// Cons for Tuple1 to Tuple22
179179
private def specialCaseCons(x: Any, self: Tuple): Tuple = {
180180
(self: Any) match {
181-
case self: Unit =>
181+
case Tuple0 =>
182182
Tuple1(x)
183183
case self: Tuple1[_] =>
184184
Tuple2(x, self._1)
@@ -278,15 +278,15 @@ object Tuple {
278278
}
279279

280280
def size(self: Tuple): Int = (self: Any) match {
281-
case self: Unit => 0
281+
case Tuple0 => 0
282282
case self: Product => self.productArity
283283
}
284284

285285
// Tail for Tuple1 to Tuple22
286286
private def specialCaseTail(self: Tuple): Tuple = {
287287
(self: Any) match {
288288
case self: Tuple1[_] =>
289-
()
289+
Tuple0.asInstanceOf[Tuple]
290290
case self: Tuple2[_, _] =>
291291
Tuple1(self._2)
292292
case self: Tuple3[_, _, _] =>
@@ -356,7 +356,7 @@ object Tuple {
356356

357357
def apply(self: NonEmptyTuple, n: Int): Any = {
358358
(self: Any) match {
359-
// case self: Unit => throw new IndexOutOfBoundsException(n.toString)
359+
// case EmptyTuple => throw new IndexOutOfBoundsException(n.toString)
360360
case self: Product => self.productElement(n)
361361
}
362362
}
@@ -376,7 +376,7 @@ object Tuple {
376376
val t1Size: Int = t1.size
377377
val t2Size: Int = t2.size
378378
val size = Math.min(t1Size, t2Size)
379-
if size == 0 then ()
379+
if size == 0 then Tuple0.asInstanceOf[Tuple]
380380
else Tuple.fromIArray(
381381
zipIterators(
382382
t1.asInstanceOf[Product].productIterator,
@@ -387,7 +387,7 @@ object Tuple {
387387
}
388388

389389
def map[F[_]](self: Tuple, f: [t] => t => F[t]): Tuple = (self: Any) match {
390-
case self: Unit => ()
390+
case Tuple0 => Tuple0.asInstanceOf[Tuple]
391391
case _ => fromIArray(self.asInstanceOf[Product].productIterator.map(f(_).asInstanceOf[Object]).toArray.asInstanceOf[IArray[Object]]) // TODO use toIArray
392392
}
393393

@@ -396,7 +396,7 @@ object Tuple {
396396
val selfSize: Int = self.size
397397
val actualN = Math.min(n, selfSize)
398398

399-
if (actualN == 0) ()
399+
if (actualN == 0) Tuple0.asInstanceOf[Tuple]
400400
else {
401401
val arr = (self: Any) match {
402402
case xxl: TupleXXL =>
@@ -418,7 +418,7 @@ object Tuple {
418418
val actualN = Math.min(n, size)
419419
val rem = size - actualN
420420

421-
if (rem == 0) ()
421+
if (rem == 0) Tuple0.asInstanceOf[Tuple]
422422
else {
423423
val arr = (self: Any) match {
424424
case xxl: TupleXXL =>
@@ -439,7 +439,7 @@ object Tuple {
439439
val size = self.size
440440
val actualN = Math.min(n, size)
441441
val (arr1, arr2) = (self: Any) match {
442-
case () => (Array.empty[Object], Array.empty[Object])
442+
case Tuple0 => (Array.empty[Object], Array.empty[Object])
443443
case xxl: TupleXXL =>
444444
xxl.elems.asInstanceOf[Array[Object]].splitAt(actualN)
445445
case _ =>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package scala.runtime
2+
3+
/** A tuple of 0 elements; the canonical representation of a [[scala.Product0]].
4+
*/
5+
/*case*/ object Tuple0 /*extends Product0 */ {
6+
override def toString(): String = "()"
7+
}

library/src-non-bootstrapped/scala/Tuple.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ object Tuple {
159159
*/
160160
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
161161

162+
/** Empty tuple */
163+
def apply(): Unit = ()
164+
162165
/** Convert an array into a tuple of unknown arity and types */
163166
def fromArray[T](xs: Array[T]): Tuple = {
164167
val xs2 = xs match {
@@ -187,6 +190,8 @@ object Tuple {
187190
Tuple.fromArray(p.productIterator.toArray).asInstanceOf[m.MirroredElemTypes] // TODO use toIArray of Object to avoid double/triple array copy
188191
}
189192

193+
def EmptyTuple: Unit = ()
194+
190195
/** Tuple of arbitrary non-zero arity */
191196
sealed trait NonEmptyTuple extends Tuple with Product {
192197
import Tuple._

library/src/scala/internal/quoted/Matcher.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ private[quoted] object Matcher {
446446
private object Matching {
447447

448448
def notMatched: Matching = None
449-
val matched: Matching = Some(())
449+
val matched: Matching = Some(Tuple())
450450
def matched(x: Any): Matching = Some(Tuple1(x))
451451

452452
def (self: Matching) asOptionOfTuple: Option[Tuple] = self

library/src/scala/tasty/Reflection.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,6 +2574,18 @@ class Reflection(private[scala] val internal: CompilerInterface) { self =>
25742574

25752575
/** The type for `scala.String`. */
25762576
def StringType: Type = internal.Definitions_StringType
2577+
2578+
/** The type for `scala.Tuple`. */
2579+
def TupleType: Type = internal.Definitions_TupleType
2580+
2581+
/** The type for `scala.EmptyTuple`. */
2582+
def EmptyTupleType: Type = internal.Definitions_EmptyTupleType
2583+
2584+
/** The type for `scala.NonEmptyTuple`. */
2585+
def NonEmptyTupleType: Type = internal.Definitions_NonEmptyTupleType
2586+
2587+
/** The type for `scala.*:`. */
2588+
def TupleConsType: Type = internal.Definitions_TupleConsType
25772589
}
25782590

25792591

0 commit comments

Comments
 (0)