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