@@ -285,7 +285,8 @@ object desugar {
285
285
case _ => false
286
286
}
287
287
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 )
289
290
val isValueClass = parents.nonEmpty && isAnyVal(parents.head)
290
291
// This is not watertight, but `extends AnyVal` will be replaced by `inline` later.
291
292
@@ -332,6 +333,7 @@ object desugar {
332
333
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
333
334
// def isDefined = true
334
335
// def productArity = N
336
+ // def productElement(i: Int): Any = i match { ... }
335
337
// def _1 = this.p1
336
338
// ...
337
339
// def _N = this.pN
@@ -342,14 +344,35 @@ object desugar {
342
344
// Note: copy default parameters need @uncheckedVariance; see
343
345
// neg/t1843-variances.scala for a test case. The test would give
344
346
// 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 = {
349
371
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 = {
353
376
def isRepeated (tree : Tree ): Boolean = tree match {
354
377
case PostfixOp (_, nme.raw.STAR ) => true
355
378
case ByNameTypeTree (tree1) => isRepeated(tree1)
@@ -359,34 +382,32 @@ object desugar {
359
382
case ValDef (_, tpt, _) => isRepeated(tpt)
360
383
case _ => false
361
384
})
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
+ }
376
396
}
397
+
398
+ if (isCaseClass)
399
+ productElement :: productArity :: copyMeths ::: productElemMeths.toList
400
+ else if (isCaseObject)
401
+ productElement :: productArity :: Nil
377
402
else Nil
403
+ }
378
404
379
405
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
- }
385
406
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
390
411
391
412
// The thicket which is the desugared version of the companion object
392
413
// synthetic object C extends parentTpt { defs }
0 commit comments