@@ -45,22 +45,45 @@ object TypeUtils {
45
45
case ps => ps.reduceLeft(AndType (_, _))
46
46
}
47
47
48
- /** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs */
49
- def tupleElementTypes (using Context ): Option [List [Type ]] = self.dealias match {
50
- case AppliedType (tycon, hd :: tl :: Nil ) if tycon.isRef(defn.PairClass ) =>
51
- tl.tupleElementTypes.map(hd :: _)
52
- case self : SingletonType =>
53
- if self.termSymbol == defn.EmptyTupleModule then Some (Nil ) else None
54
- case AndType (tp1, tp2) =>
55
- // We assume that we have the following property:
56
- // (T1, T2, ..., Tn) & (U1, U2, ..., Un) = (T1 & U1, T2 & U2, ..., Tn & Un)
57
- tp1.tupleElementTypes.zip(tp2.tupleElementTypes).map { case (t1, t2) => t1.intersect(t2) }
58
- case OrType (tp1, tp2) =>
59
- None // We can't combine the type of two tuples
60
- case _ =>
61
- if defn.isTupleClass(self.typeSymbol) then Some (self.dealias.argInfos)
62
- else None
63
- }
48
+ /** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs
49
+ */
50
+ def tupleElementTypes (using Context ): Option [List [Type ]] =
51
+ tupleElementTypesUpTo(Int .MaxValue )
52
+
53
+ /** The element types of this tuple type, which can be made up of EmptyTuple, TupleX and `*:` pairs
54
+ * @param bound The maximum number of elements that needs generating minus 1
55
+ * The generation will stop once more than bound elems have been generated
56
+ * @param normalize If true, normalize and dealias at each step.
57
+ * If false, never normalize and dealias only to find *:
58
+ * and EmptyTuple types. This is useful for printing.
59
+ */
60
+ def tupleElementTypesUpTo (bound : Int , normalize : Boolean = true )(using Context ): Option [List [Type ]] =
61
+ def recur (tp : Type , bound : Int ): Option [List [Type ]] =
62
+ if bound < 0 then Some (Nil )
63
+ else (if normalize then tp.normalized else tp).dealias match
64
+ case AppliedType (tycon, hd :: tl :: Nil ) if tycon.isRef(defn.PairClass ) =>
65
+ recur(tl, bound - 1 ).map(hd :: _)
66
+ case tp : AppliedType if defn.isTupleNType(tp) && normalize =>
67
+ Some (tp.args) // if normalize is set, use the dealiased tuple
68
+ // otherwise rely on the default case below to print unaliased tuples.
69
+ case tp : SingletonType =>
70
+ if tp.termSymbol == defn.EmptyTupleModule then Some (Nil ) else None
71
+ case _ =>
72
+ if defn.isTupleClass(tp.typeSymbol) && ! normalize then Some (tp.dealias.argInfos)
73
+ else None
74
+ recur(self.stripTypeVar, bound)
75
+
76
+ /** Is this a generic tuple that would fit into the range 1..22,
77
+ * but is not already an instance of one of Tuple1..22?
78
+ * In this case we need to cast it to make the TupleN/ members accessible.
79
+ * This works only for generic tuples of known size up to 22.
80
+ */
81
+ def isSmallGenericTuple (using Context ): Boolean =
82
+ self.derivesFrom(defn.PairClass )
83
+ && ! defn.isTupleNType(self.widenDealias)
84
+ && self.widenTermRefExpr.tupleElementTypesUpTo(Definitions .MaxTupleArity ).match
85
+ case Some (elems) if elems.length <= Definitions .MaxTupleArity => true
86
+ case _ => false
64
87
65
88
/** The `*:` equivalent of an instance of a Tuple class */
66
89
def toNestedPairs (using Context ): Type =
0 commit comments