@@ -45,22 +45,45 @@ object TypeUtils {
4545 case ps => ps.reduceLeft(AndType (_, _))
4646 }
4747
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
6487
6588 /** The `*:` equivalent of an instance of a Tuple class */
6689 def toNestedPairs (using Context ): Type =
0 commit comments