Skip to content

Commit 569e4b9

Browse files
committed
treat EmptyTuple type alias the same as the aliased EmptyTuple.type and use EmptyTuple in compiler-generated code
1 parent 24463aa commit 569e4b9

File tree

8 files changed

+29
-25
lines changed

8 files changed

+29
-25
lines changed

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

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

14961496
/** Creates the nested pairs type tree repesentation of the type trees in `ts` */
14971497
def nestedPairsTypeTree(ts: List[Tree])(using Context): Tree =
1498-
ts.foldRight[Tree](TypeTree(defn.EmptyTupleModule.termRef))((x, acc) => AppliedTypeTree(TypeTree(defn.PairClass.typeRef), x :: acc :: Nil))
1498+
ts.foldRight[Tree](TypeTree(defn.EmptyTupleType.typeRef))((x, acc) => AppliedTypeTree(TypeTree(defn.PairClass.typeRef), x :: acc :: Nil))
14991499

15001500
/** Replaces all positions in `tree` with zero-extent positions */
15011501
private def focusPositions(tree: Tree)(using Context): Tree = {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ class Definitions {
904904
@tu lazy val TupleTypeRef: TypeRef = requiredClassRef("scala.Tuple")
905905
def TupleClass(using Context): ClassSymbol = TupleTypeRef.symbol.asClass
906906
@tu lazy val Tuple_cons: Symbol = TupleClass.requiredMethod("*:")
907+
@tu lazy val EmptyTupleType: Symbol = ScalaPackageVal.requiredType("EmptyTuple")
907908
@tu lazy val EmptyTupleModule: Symbol = requiredModule("scala.EmptyTuple")
908909
@tu lazy val NonEmptyTupleTypeRef: TypeRef = requiredClassRef("scala.NonEmptyTuple")
909910
def NonEmptyTupleClass(using Context): ClassSymbol = NonEmptyTupleTypeRef.symbol.asClass

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
689689
}
690690

691691
private def erasePair(tp: Type)(using Context): Type = {
692-
val arity = tp.tupleArity
692+
val arity = tp.tupleArity(underErasure = true)
693693
if (arity < 0) defn.ProductClass.typeRef
694694
else if (arity <= Definitions.MaxTupleArity) defn.TupleType(arity).nn
695695
else defn.TupleXXLClass.typeRef

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ object TypeOps:
840840
}
841841

842842
def nestedPairs(ts: List[Type])(using Context): Type =
843-
ts.foldRight(defn.EmptyTupleModule.termRef: Type)(defn.PairClass.typeRef.appliedTo(_, _))
843+
ts.foldRight(defn.EmptyTupleType.typeRef: Type)(defn.PairClass.typeRef.appliedTo(_, _))
844844

845845
class StripTypeVarsMap(using Context) extends TypeMap:
846846
def apply(tp: Type) = mapOver(tp).stripTypeVar

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

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,31 +51,34 @@ object TypeUtils {
5151

5252
/** The arity of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs,
5353
* or -1 if this is not a tuple type.
54+
* We treat the arity under erasure specially to erase `T *: EmptyTuple` to `Product`
55+
* but `T *: EmptyTuple.type` to `Tuple1` for binary compatibility.
5456
*/
55-
def tupleArity(using Context): Int = self match {
57+
def tupleArity(underErasure: Boolean)(using Context): Int = self match
5658
case AppliedType(tycon, _ :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
57-
val arity = tl.tupleArity
58-
if (arity < 0) arity else arity + 1
59-
case self: SingletonType =>
60-
if self.termSymbol == defn.EmptyTupleModule then 0 else -1
61-
case self if defn.isTupleClass(self.classSymbol) =>
62-
self.dealias.argInfos.length
59+
val arity = tl.tupleArity(underErasure)
60+
if arity < 0 then arity else arity + 1
6361
case _ =>
64-
-1
65-
}
62+
if self.termSymbol == defn.EmptyTupleModule then
63+
if !underErasure || self.isInstanceOf[SingletonType] then 0 else -1
64+
else if defn.isTupleClass(self.classSymbol) then
65+
self.widenTermRefExpr.dealias.argInfos.length
66+
else
67+
-1
68+
69+
inline def tupleArity(using Context): Int = tupleArity(underErasure = false)
6670

6771
/** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs */
68-
def tupleElementTypes(using Context): List[Type] = self match {
72+
def tupleElementTypes(using Context): List[Type] = self match
6973
case AppliedType(tycon, hd :: tl :: Nil) if tycon.isRef(defn.PairClass) =>
7074
hd :: tl.tupleElementTypes
71-
case self: SingletonType =>
72-
assert(self.termSymbol == defn.EmptyTupleModule, "not a tuple")
73-
Nil
74-
case self if defn.isTupleClass(self.classSymbol) =>
75-
self.dealias.argInfos
76-
case _ =>
77-
throw new AssertionError("not a tuple")
78-
}
75+
case _ =>
76+
if self.termSymbol == defn.EmptyTupleModule then
77+
Nil
78+
else if defn.isTupleClass(self.classSymbol) then
79+
self.widenTermRefExpr.dealias.argInfos
80+
else
81+
throw new AssertionError("not a tuple")
7982

8083
/** The `*:` equivalent of an instance of a Tuple class */
8184
def toNestedPairs(using Context): Type =

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2772,7 +2772,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27722772
if ctx.mode.is(Mode.Type) then typedType(_, _, mapPatternBounds = true)
27732773
else typed(_, _))
27742774
if (ctx.mode.is(Mode.Type))
2775-
elems.foldRight(TypeTree(defn.EmptyTupleModule.termRef): Tree)((elemTpt, elemTpts) =>
2775+
elems.foldRight(TypeTree(defn.EmptyTupleType.typeRef): Tree)((elemTpt, elemTpts) =>
27762776
AppliedTypeTree(TypeTree(defn.PairClass.typeRef), List(elemTpt, elemTpts)))
27772777
.withSpan(tree.span)
27782778
else {

compiler/test-resources/repl/i5218

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ val tuple: (Int, String, Long) = (1,2,3)
33
scala> 0.0 *: tuple
44
val res0: (Double, Int, String, Long) = (0.0,1,2,3)
55
scala> tuple ++ tuple
6-
val res1: Int *: String *: Long *: tuple.type = (1,2,3,1,2,3)
6+
val res1: (Int, String, Long, Int, String, Long) = (1,2,3,1,2,3)

tests/neg/i12049.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
-- Error: tests/neg/i12049.scala:22:26 ---------------------------------------------------------------------------------
2727
22 |val z3: (A, B, A) = ??? : Reverse[(A, B, A)] // error
2828
| ^
29-
| Match type reduction failed since selector A *: EmptyTuple.type
29+
| Match type reduction failed since selector A *: EmptyTuple
3030
| matches none of the cases
3131
|
3232
| case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)]
@@ -56,7 +56,7 @@
5656
-- Error: tests/neg/i12049.scala:26:29 ---------------------------------------------------------------------------------
5757
26 |val _ = summon[(A, B, A) =:= Reverse[(A, B, A)]] // error
5858
| ^
59-
| Match type reduction failed since selector A *: EmptyTuple.type
59+
| Match type reduction failed since selector A *: EmptyTuple
6060
| matches none of the cases
6161
|
6262
| case t1 *: t2 *: ts => Tuple.Concat[Reverse[ts], (t2, t1)]

0 commit comments

Comments
 (0)