aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/ast
diff options
context:
space:
mode:
authorFelix Mulder <felix.mulder@gmail.com>2017-04-11 12:01:17 +0200
committerGitHub <noreply@github.com>2017-04-11 12:01:17 +0200
commit4868fb29580a67c7a1560d5c1c7cc658e2634359 (patch)
tree1deed7fb92912f09b810e905e351fe4cd796cc6b /compiler/src/dotty/tools/dotc/ast
parent579571e05a08120133173933e7eaf2555846d1d7 (diff)
parent198b5cec531a8e0d6c121cc425e19a54b7818868 (diff)
downloaddotty-4868fb29580a67c7a1560d5c1c7cc658e2634359.tar.gz
dotty-4868fb29580a67c7a1560d5c1c7cc658e2634359.tar.bz2
dotty-4868fb29580a67c7a1560d5c1c7cc658e2634359.zip
Merge pull request #1938 from dotty-staging/named-based-patmat
Change case class desugaring and decouple Products and name-based-pattern-matching
Diffstat (limited to 'compiler/src/dotty/tools/dotc/ast')
-rw-r--r--compiler/src/dotty/tools/dotc/ast/Desugar.scala83
1 files changed, 55 insertions, 28 deletions
diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
index 111382b18..2722d91eb 100644
--- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala
+++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala
@@ -353,8 +353,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
@@ -362,17 +360,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)
@@ -382,24 +401,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) = {
@@ -407,13 +431,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)