@@ -47,11 +47,22 @@ object Applications {
47
47
48
48
/** Does `tp` fit the "product match" conditions as an unapply result type
49
49
* for a pattern with `numArgs` subpatterns?
50
- * This is the case of `tp` has members `_1` to `_N` where `N == numArgs`.
50
+ * This is the case if `tp` has members `_1` to `_N` where `N == numArgs`.
51
51
*/
52
52
def isProductMatch (tp : Type , numArgs : Int , errorPos : SourcePosition = NoSourcePosition )(implicit ctx : Context ): Boolean =
53
53
numArgs > 0 && productArity(tp, errorPos) == numArgs
54
54
55
+ /** Does `tp` fit the "product-seq match" conditions as an unapply result type
56
+ * for a pattern with `numArgs` subpatterns?
57
+ * This is the case if (1) `tp` has members `_1` to `_N` where `N <= numArgs + 1`.
58
+ * (2) `tp._N` conforms to Seq match
59
+ */
60
+ def isProductSeqMatch (tp : Type , numArgs : Int , errorPos : SourcePosition = NoSourcePosition )(implicit ctx : Context ): Boolean = {
61
+ val arity = productArity(tp, errorPos)
62
+ arity > 0 && arity <= numArgs + 1 &&
63
+ unapplySeqTypeElemTp(productSelectorTypes(tp, errorPos).last).exists
64
+ }
65
+
55
66
/** Does `tp` fit the "get match" conditions as an unapply result type?
56
67
* This is the case of `tp` has a `get` member as well as a
57
68
* parameterless `isEmpty` member of result type `Boolean`.
@@ -60,6 +71,39 @@ object Applications {
60
71
extractorMemberType(tp, nme.isEmpty, errorPos).isRef(defn.BooleanClass ) &&
61
72
extractorMemberType(tp, nme.get, errorPos).exists
62
73
74
+ /** If `getType` is of the form:
75
+ * ```
76
+ * {
77
+ * def lengthCompare(len: Int): Int // or, def length: Int
78
+ * def apply(i: Int): T = a(i)
79
+ * def drop(n: Int): scala.Seq[T]
80
+ * def toSeq: scala.Seq[T]
81
+ * }
82
+ * ```
83
+ * returns `T`, otherwise NoType.
84
+ */
85
+ def unapplySeqTypeElemTp (getTp : Type )(implicit ctx : Context ): Type = {
86
+ def lengthTp = ExprType (defn.IntType )
87
+ def lengthCompareTp = MethodType (List (defn.IntType ), defn.IntType )
88
+ def applyTp (elemTp : Type ) = MethodType (List (defn.IntType ), elemTp)
89
+ def dropTp (elemTp : Type ) = MethodType (List (defn.IntType ), defn.SeqType .appliedTo(elemTp))
90
+ def toSeqTp (elemTp : Type ) = ExprType (defn.SeqType .appliedTo(elemTp))
91
+
92
+ // the result type of `def apply(i: Int): T`
93
+ val elemTp = getTp.member(nme.apply).suchThat(_.info <:< applyTp(WildcardType )).info.resultType
94
+
95
+ def hasMethod (name : Name , tp : Type ) =
96
+ getTp.member(name).suchThat(getTp.memberInfo(_) <:< tp).exists
97
+
98
+ val isValid =
99
+ elemTp.exists &&
100
+ (hasMethod(nme.lengthCompare, lengthCompareTp) || hasMethod(nme.length, lengthTp)) &&
101
+ hasMethod(nme.drop, dropTp(elemTp)) &&
102
+ hasMethod(nme.toSeq, toSeqTp(elemTp))
103
+
104
+ if (isValid) elemTp else NoType
105
+ }
106
+
63
107
def productSelectorTypes (tp : Type , errorPos : SourcePosition )(implicit ctx : Context ): List [Type ] = {
64
108
def tupleSelectors (n : Int , tp : Type ): List [Type ] = {
65
109
val sel = extractorMemberType(tp, nme.selectorName(n), errorPos)
@@ -89,9 +133,17 @@ object Applications {
89
133
if (args.length > 1 && ! (tp.derivesFrom(defn.SeqClass ))) {
90
134
val sels = productSelectorTypes(tp, pos)
91
135
if (sels.length == args.length) sels
136
+ else if (isProductSeqMatch(tp, args.length, pos)) productSeqSelectors(tp, args, pos)
92
137
else tp :: Nil
93
138
} else tp :: Nil
94
139
140
+ def productSeqSelectors (tp : Type , args : List [untpd.Tree ], pos : SourcePosition )(implicit ctx : Context ): List [Type ] = {
141
+ val selTps = productSelectorTypes(tp, pos)
142
+ val arity = selTps.length
143
+ val elemTp = unapplySeqTypeElemTp(selTps.last)
144
+ (0 until args.length).map(i => if (i < arity - 1 ) selTps(i) else elemTp).toList
145
+ }
146
+
95
147
def unapplyArgs (unapplyResult : Type , unapplyFn : Tree , args : List [untpd.Tree ], pos : SourcePosition )(implicit ctx : Context ): List [Type ] = {
96
148
97
149
val unapplyName = unapplyFn.symbol.name
@@ -103,43 +155,11 @@ object Applications {
103
155
Nil
104
156
}
105
157
106
- /** If `getType` is of the form:
107
- * ```
108
- * {
109
- * def lengthCompare(len: Int): Int // or, def length: Int
110
- * def apply(i: Int): T = a(i)
111
- * def drop(n: Int): scala.Seq[T]
112
- * def toSeq: scala.Seq[T]
113
- * }
114
- * ```
115
- * returns `T`, otherwise NoType.
116
- */
117
- def unapplySeqTypeElemTp (getTp : Type ): Type = {
118
- def lengthTp = ExprType (defn.IntType )
119
- def lengthCompareTp = MethodType (List (defn.IntType ), defn.IntType )
120
- def applyTp (elemTp : Type ) = MethodType (List (defn.IntType ), elemTp)
121
- def dropTp (elemTp : Type ) = MethodType (List (defn.IntType ), defn.SeqType .appliedTo(elemTp))
122
- def toSeqTp (elemTp : Type ) = defn.SeqType .appliedTo(elemTp)
123
-
124
- // the result type of `def apply(i: Int): T`
125
- val elemTp = getTp.member(nme.apply).suchThat(_.info <:< applyTp(WildcardType )).info.resultType
126
-
127
- def hasMethod (name : Name , tp : Type ) =
128
- getTp.member(name).suchThat(getTp.memberInfo(_) <:< tp).exists
129
-
130
- val isValid =
131
- elemTp.exists &&
132
- (hasMethod(nme.lengthCompare, lengthCompareTp) || hasMethod(nme.length, lengthTp)) &&
133
- hasMethod(nme.drop, dropTp(elemTp)) &&
134
- hasMethod(nme.toSeq, toSeqTp(elemTp))
135
-
136
- if (isValid) elemTp else NoType
137
- }
138
-
139
- if (unapplyName == nme.unapplySeq) {
158
+ if (unapplyName == nme.unapplySeq) { // && ctx.scala2Mode
140
159
if (isGetMatch(unapplyResult, pos)) {
141
160
val elemTp = unapplySeqTypeElemTp(getTp)
142
161
if (elemTp.exists) args.map(Function .const(elemTp))
162
+ else if (isProductSeqMatch(getTp, args.length, pos)) productSeqSelectors(getTp, args, pos)
143
163
else fail
144
164
}
145
165
else fail
@@ -148,6 +168,8 @@ object Applications {
148
168
assert(unapplyName == nme.unapply)
149
169
if (isProductMatch(unapplyResult, args.length, pos))
150
170
productSelectorTypes(unapplyResult, pos)
171
+ else if (isProductSeqMatch(unapplyResult, args.length, pos))
172
+ productSeqSelectors(unapplyResult, args, pos)
151
173
else if (isGetMatch(unapplyResult, pos))
152
174
getUnapplySelectors(getTp, args, pos)
153
175
else if (unapplyResult.widenSingleton isRef defn.BooleanClass )
0 commit comments