aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Blanvillain <olivier.blanvillain@gmail.com>2017-04-06 18:52:58 +0200
committerOlivier Blanvillain <olivier.blanvillain@gmail.com>2017-04-06 18:52:58 +0200
commitc0ff8adcb4f44a0b01077495a7626d201f8100d5 (patch)
tree4cd55318e625cfdf844075a6c1ecfb2b760422bb
parent0ad5956f1a36b32061374095cb69ca9b4364d450 (diff)
downloaddotty-c0ff8adcb4f44a0b01077495a7626d201f8100d5.tar.gz
dotty-c0ff8adcb4f44a0b01077495a7626d201f8100d5.tar.bz2
dotty-c0ff8adcb4f44a0b01077495a7626d201f8100d5.zip
Generate synthetic productElement/productArity methods above 22
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala83
-rw-r--r--compiler/src/dotty/tools/dotc/core/Definitions.scala1
2 files changed, 56 insertions, 28 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 66fc6bf84..45b339727 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -352,8 +352,6 @@ object desugar {
lazy val creatorExpr = New(classTypeRef, constrVparamss nestedMap refOfDef)
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
- // def isDefined = true
- // def productArity = N
// def _1 = this.p1
// ...
// def _N = this.pN
@@ -361,17 +359,38 @@ object desugar {
// pN: TN = pN: @uncheckedVariance)(moreParams) =
// new C[...](p1, ..., pN)(moreParams)
//
+ // Above arity 22 we also synthesize:
+ // def productArity = N
+ // def productElement(i: Int): Any = i match { ... }
+ //
// Note: copy default parameters need @uncheckedVariance; see
// neg/t1843-variances.scala for a test case. The test would give
// two errors without @uncheckedVariance, one of them spurious.
- val caseClassMeths =
- if (isCaseClass) {
- def syntheticProperty(name: TermName, rhs: Tree) =
- DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
+ val caseClassMeths = {
+ def syntheticProperty(name: TermName, rhs: Tree) =
+ DefDef(name, Nil, Nil, TypeTree(), rhs).withMods(synthetic)
+ def productArity = syntheticProperty(nme.productArity, Literal(Constant(arity)))
+ def productElement = {
+ val param = makeSyntheticParameter(tpt = ref(defn.IntType))
+ // case N => _${N + 1}
+ val cases = 0.until(arity).map { i =>
+ CaseDef(Literal(Constant(i)), EmptyTree, Select(This(EmptyTypeIdent), nme.selectorName(i)))
+ }
+ val ioob = ref(defn.IndexOutOfBoundsException.typeRef)
+ val error = Throw(New(ioob, List(List(Select(refOfDef(param), nme.toString_)))))
+ // case _ => throw new IndexOutOfBoundsException(i.toString)
+ val defaultCase = CaseDef(untpd.Ident(nme.WILDCARD), EmptyTree, error)
+ val body = Match(refOfDef(param), (cases :+ defaultCase).toList)
+ DefDef(nme.productElement, Nil, List(List(param)), TypeTree(defn.AnyType), body)
+ .withMods(synthetic)
+ }
+ def productElemMeths = {
val caseParams = constrVparamss.head.toArray
- val productElemMeths =
- for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
- yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name))
+ for (i <- 0 until arity if nme.selectorName(i) `ne` caseParams(i).name)
+ yield syntheticProperty(nme.selectorName(i), Select(This(EmptyTypeIdent), caseParams(i).name))
+ }
+ def enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
+ def copyMeths = {
def isRepeated(tree: Tree): Boolean = tree match {
case PostfixOp(_, Ident(nme.raw.STAR)) => true
case ByNameTypeTree(tree1) => isRepeated(tree1)
@@ -381,24 +400,29 @@ object desugar {
case ValDef(_, tpt, _) => isRepeated(tpt)
case _ => false
})
-
- val copyMeths =
- if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
- else {
- def copyDefault(vparam: ValDef) =
- makeAnnotated("scala.annotation.unchecked.uncheckedVariance", refOfDef(vparam))
- val copyFirstParams = derivedVparamss.head.map(vparam =>
- cpy.ValDef(vparam)(rhs = copyDefault(vparam)))
- val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
- cpy.ValDef(vparam)(rhs = EmptyTree))
- DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr)
- .withMods(synthetic) :: Nil
- }
-
- val enumTagMeths = if (isEnumCase) enumTagMeth(CaseKind.Class)._1 :: Nil else Nil
- copyMeths ::: enumTagMeths ::: productElemMeths.toList
+ if (mods.is(Abstract) || hasRepeatedParam) Nil // cannot have default arguments for repeated parameters, hence copy method is not issued
+ else {
+ def copyDefault(vparam: ValDef) =
+ makeAnnotated("scala.annotation.unchecked.uncheckedVariance", refOfDef(vparam))
+ val copyFirstParams = derivedVparamss.head.map(vparam =>
+ cpy.ValDef(vparam)(rhs = copyDefault(vparam)))
+ val copyRestParamss = derivedVparamss.tail.nestedMap(vparam =>
+ cpy.ValDef(vparam)(rhs = EmptyTree))
+ DefDef(nme.copy, derivedTparams, copyFirstParams :: copyRestParamss, TypeTree(), creatorExpr)
+ .withMods(synthetic) :: Nil
+ }
}
+
+ // Above MaxTupleArity we extend Product instead of ProductN, in this
+ // case we need to synthesise productElement & productArity.
+ def largeProductMeths =
+ if (arity > Definitions.MaxTupleArity) productElement :: productArity :: Nil
+ else Nil
+
+ if (isCaseClass)
+ largeProductMeths ::: copyMeths ::: enumTagMeths ::: productElemMeths.toList
else Nil
+ }
def anyRef = ref(defn.AnyRefAlias.typeRef)
def productConstr(n: Int) = {
@@ -406,13 +430,16 @@ object desugar {
val targs = constrVparamss.head map (_.tpt)
if (targs.isEmpty) tycon else AppliedTypeTree(tycon, targs)
}
+ def product =
+ if (arity > Definitions.MaxTupleArity) scalaDot(nme.Product.toTypeName)
+ else productConstr(arity)
- // Case classes and case objects get a ProductN parent
+ // Case classes and case objects get Product/ProductN parents
var parents1 = parents
if (isEnumCase && parents.isEmpty)
parents1 = enumClassTypeRef :: Nil
- if (mods.is(Case) && arity <= Definitions.MaxTupleArity)
- parents1 = parents1 :+ productConstr(arity) // TODO: This also adds Product0 to caes objects. Do we want that?
+ if (mods.is(Case))
+ parents1 = parents1 :+ product // TODO: This also adds Product0 to case objects. Do we want that?
if (isEnum)
parents1 = parents1 :+ ref(defn.EnumType)
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index b70fcb093..337f48064 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -477,6 +477,7 @@ class Definitions {
lazy val JavaCloneableClass = ctx.requiredClass("java.lang.Cloneable")
lazy val NullPointerExceptionClass = ctx.requiredClass("java.lang.NullPointerException")
+ lazy val IndexOutOfBoundsException = ctx.requiredClass("java.lang.IndexOutOfBoundsException")
lazy val ClassClass = ctx.requiredClass("java.lang.Class")
lazy val BoxedNumberClass = ctx.requiredClass("java.lang.Number")
lazy val ThrowableClass = ctx.requiredClass("java.lang.Throwable")