Skip to content

Commit 9df79a1

Browse files
committed
treat EmptyTuple type alias the same as the aliased EmptyTuple.type and use EmptyTuple in compiler-generated code
1 parent c0dcf97 commit 9df79a1

File tree

8 files changed

+28
-24
lines changed

8 files changed

+28
-24
lines changed

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

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

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

14861486
/** Replaces all positions in `tree` with zero-extent positions */
14871487
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
@@ -858,6 +858,7 @@ class Definitions {
858858
@tu lazy val TupleTypeRef: TypeRef = requiredClassRef("scala.Tuple")
859859
def TupleClass(using Context): ClassSymbol = TupleTypeRef.symbol.asClass
860860
@tu lazy val Tuple_cons: Symbol = TupleClass.requiredMethod("*:")
861+
@tu lazy val EmptyTupleType: Symbol = ScalaPackageVal.requiredType("EmptyTuple")
861862
@tu lazy val EmptyTupleModule: Symbol = requiredModule("scala.EmptyTuple")
862863
@tu lazy val NonEmptyTupleTypeRef: TypeRef = requiredClassRef("scala.NonEmptyTuple")
863864
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
@@ -686,7 +686,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
686686
}
687687

688688
private def erasePair(tp: Type)(using Context): Type = {
689-
val arity = tp.tupleArity
689+
val arity = tp.tupleArity(underErasure = true)
690690
if (arity < 0) defn.ProductClass.typeRef
691691
else if (arity <= Definitions.MaxTupleArity) defn.TupleType(arity)
692692
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: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,31 +49,34 @@ object TypeUtils {
4949

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

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

7881
/** The `*:` equivalent of an instance of a Tuple class */
7982
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
@@ -2727,7 +2727,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
27272727
if ctx.mode.is(Mode.Type) then typedType(_, _, mapPatternBounds = true)
27282728
else typed(_, _))
27292729
if (ctx.mode.is(Mode.Type))
2730-
elems.foldRight(TypeTree(defn.EmptyTupleModule.termRef): Tree)((elemTpt, elemTpts) =>
2730+
elems.foldRight(TypeTree(defn.EmptyTupleType.typeRef): Tree)((elemTpt, elemTpts) =>
27312731
AppliedTypeTree(TypeTree(defn.PairClass.typeRef), List(elemTpt, elemTpts)))
27322732
.withSpan(tree.span)
27332733
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)