@@ -23,6 +23,7 @@ import scala.language.postfixOps
23
23
* def hashCode(): Int
24
24
* def canEqual(other: Any): Boolean
25
25
* def toString(): String
26
+ * def productElement(i: Int): Any
26
27
* def productArity: Int
27
28
* def productPrefix: String
28
29
* Special handling:
@@ -44,7 +45,7 @@ class SyntheticMethods(thisTransformer: DenotTransformer) {
44
45
if (myValueSymbols.isEmpty) {
45
46
myValueSymbols = List (defn.Any_hashCode , defn.Any_equals )
46
47
myCaseSymbols = myValueSymbols ++ List (defn.Any_toString , defn.Product_canEqual ,
47
- defn.Product_productArity , defn.Product_productPrefix )
48
+ defn.Product_productArity , defn.Product_productPrefix , defn. Product_productElement )
48
49
}
49
50
50
51
def valueSymbols (implicit ctx : Context ) = { initSymbols; myValueSymbols }
@@ -91,11 +92,47 @@ class SyntheticMethods(thisTransformer: DenotTransformer) {
91
92
case nme.canEqual_ => vrefss => canEqualBody(vrefss.head.head)
92
93
case nme.productArity => vrefss => Literal (Constant (accessors.length))
93
94
case nme.productPrefix => ownName
95
+ case nme.productElement => vrefss => productElementBody(accessors.length, vrefss.head.head)
94
96
}
95
97
ctx.log(s " adding $synthetic to $clazz at ${ctx.phase}" )
96
98
DefDef (synthetic, syntheticRHS(ctx.withOwner(synthetic)))
97
99
}
98
100
101
+ /** The class
102
+ *
103
+ * ```
104
+ * case class C(x: T, y: T)
105
+ * ```
106
+ *
107
+ * gets the `productElement` method:
108
+ *
109
+ * ```
110
+ * def productElement(index: Int): Any = index match {
111
+ * case 0 => this._1
112
+ * case 1 => this._2
113
+ * case _ => throw new IndexOutOfBoundsException(index.toString)
114
+ * }
115
+ * ```
116
+ */
117
+ def productElementBody (arity : Int , index : Tree )(implicit ctx : Context ): Tree = {
118
+ val ioob = defn.IndexOutOfBoundsException .typeRef
119
+ // That's not ioob.typeSymbol.primaryConstructor, this is the other one
120
+ // that takes a String argument.
121
+ val constructor = ioob.typeSymbol.info.decls.toList.tail.head.asTerm
122
+ val stringIndex = Apply (Select (index, nme.toString_), Nil )
123
+ val error = Throw (New (ioob, constructor, List (stringIndex)))
124
+
125
+ // case _ => throw new IndexOutOfBoundsException(i.toString)
126
+ val defaultCase = CaseDef (Underscore (defn.IntType ), EmptyTree , error)
127
+
128
+ // case N => _${N + 1}
129
+ val cases = 0 .until(arity).map { i =>
130
+ CaseDef (Literal (Constant (i)), EmptyTree , Select (This (clazz), nme.selectorName(i)))
131
+ }
132
+
133
+ Match (index, (cases :+ defaultCase).toList)
134
+ }
135
+
99
136
/** The class
100
137
*
101
138
* case class C(x: T, y: U)
0 commit comments