@@ -285,7 +285,8 @@ object desugar {
285285 case _ => false
286286 }
287287
288- val isCaseClass = mods.is(Case ) && ! mods.is(Module )
288+ val isCaseClass = mods.is(Case ) && ! mods.is(Module )
289+ val isCaseObject = mods.is(Case ) && mods.is(Module )
289290 val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
290291 // This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
291292
@@ -332,6 +333,7 @@ object desugar {
332333 // Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
333334 // def isDefined = true
334335 // def productArity = N
336+ // def productElement(i: Int): Any = i match { ... }
335337 // def _1 = this.p1
336338 // ...
337339 // def _N = this.pN
@@ -342,14 +344,35 @@ object desugar {
342344 // Note: copy default parameters need @uncheckedVariance; see
343345 // neg/t1843-variances.scala for a test case. The test would give
344346 // two errors without @uncheckedVariance, one of them spurious.
345- val caseClassMeths =
346- if (isCaseClass) {
347- def syntheticProperty (name : TermName , rhs : Tree ) =
348- DefDef (name, Nil , Nil , TypeTree (), rhs).withMods(synthetic)
347+ val caseClassMeths = {
348+ def syntheticProperty (name : TermName , rhs : Tree ) =
349+ DefDef (name, Nil , Nil , TypeTree (), rhs).withMods(synthetic)
350+ // The override here is less than ideal: user defined productArity / productElement
351+ // methods would be silently ignored. This is necessary to compile `scala.TupleN`.
352+ // The long term solution is to remove `ProductN` entirely from stdlib.
353+ def productArity =
354+ DefDef (nme.productArity, Nil , Nil , TypeTree (), Literal (Constant (arity)))
355+ .withMods(Modifiers (Synthetic | Override ))
356+ def productElement = {
357+ val param = makeSyntheticParameter(tpt = ref(defn.IntType ))
358+ // case N => _${N + 1}
359+ val cases = 0 .until(arity).map { i =>
360+ CaseDef (Literal (Constant (i)), EmptyTree , Select (This (EmptyTypeIdent ), nme.selectorName(i)))
361+ }
362+ val ioob = ref(defn.IndexOutOfBoundsException .typeRef)
363+ val error = Throw (New (ioob, List (List (Select (refOfDef(param), nme.toString_)))))
364+ // case _ => throw new IndexOutOfBoundsException(i.toString)
365+ val defaultCase = CaseDef (untpd.Ident (nme.WILDCARD ), EmptyTree , error)
366+ val body = Match (refOfDef(param), (cases :+ defaultCase).toList)
367+ DefDef (nme.productElement, Nil , List (List (param)), TypeTree (defn.AnyType ), body)
368+ .withMods(Modifiers (Synthetic | Override ))
369+ }
370+ def productElemMeths = {
349371 val caseParams = constrVparamss.head.toArray
350- val productElemMeths =
351- for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
352- yield syntheticProperty(nme.selectorName(i), Select (This (EmptyTypeIdent ), caseParams(i).name))
372+ for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
373+ yield syntheticProperty(nme.selectorName(i), Select (This (EmptyTypeIdent ), caseParams(i).name))
374+ }
375+ def copyMeths = {
353376 def isRepeated (tree : Tree ): Boolean = tree match {
354377 case PostfixOp (_, nme.raw.STAR ) => true
355378 case ByNameTypeTree (tree1) => isRepeated(tree1)
@@ -359,34 +382,32 @@ object desugar {
359382 case ValDef (_, tpt, _) => isRepeated(tpt)
360383 case _ => false
361384 })
362-
363- val copyMeths =
364- if (mods.is(Abstract ) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
365- else {
366- def copyDefault (vparam : ValDef ) =
367- makeAnnotated(" scala.annotation.unchecked.uncheckedVariance" , refOfDef(vparam))
368- val copyFirstParams = derivedVparamss.head.map(vparam =>
369- cpy.ValDef (vparam)(rhs = copyDefault(vparam)))
370- val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
371- cpy.ValDef (vparam)(rhs = EmptyTree ))
372- DefDef (nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr)
373- .withMods(synthetic) :: Nil
374- }
375- copyMeths ::: productElemMeths.toList
385+ if (mods.is(Abstract ) || hasRepeatedParam) Nil // Cannot have default arguments for repeated parameters, hence copy method is not issued
386+ else {
387+ def copyDefault (vparam : ValDef ) =
388+ makeAnnotated(" scala.annotation.unchecked.uncheckedVariance" , refOfDef(vparam))
389+ val copyFirstParams = derivedVparamss.head.map(vparam =>
390+ cpy.ValDef (vparam)(rhs = copyDefault(vparam)))
391+ val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
392+ cpy.ValDef (vparam)(rhs = EmptyTree ))
393+ DefDef (nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr)
394+ .withMods(synthetic) :: Nil
395+ }
376396 }
397+
398+ if (isCaseClass)
399+ productElement :: productArity :: copyMeths ::: productElemMeths.toList
400+ else if (isCaseObject)
401+ productElement :: productArity :: Nil
377402 else Nil
403+ }
378404
379405 def anyRef = ref(defn.AnyRefAlias .typeRef)
380- def productConstr (n : Int ) = {
381- val tycon = scalaDot((tpnme.Product .toString + n).toTypeName)
382- val targs = constrVparamss.head map (_.tpt)
383- if (targs.isEmpty) tycon else AppliedTypeTree (tycon, targs)
384- }
385406
386- // Case classes and case objects get a ProductN parent
387- var parents1 = parents
388- if (mods.is(Case ) && arity <= Definitions . MaxTupleArity )
389- parents1 = parents1 :+ productConstr(arity)
407+ // Case classes and case objects get NameBasedPattern and Product parents
408+ val parents1 : List [ Tree ] =
409+ if (mods.is(Case )) parents :+ scalaDot(nme. Product .toTypeName) :+ scalaDot(nme. NameBasedPattern .toTypeName )
410+ else parents
390411
391412 // The thicket which is the desugared version of the companion object
392413 // synthetic object C extends parentTpt { defs }
0 commit comments