diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2017-04-11 12:01:17 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-11 12:01:17 +0200 |
commit | 4868fb29580a67c7a1560d5c1c7cc658e2634359 (patch) | |
tree | 1deed7fb92912f09b810e905e351fe4cd796cc6b /compiler/src/dotty/tools/dotc/ast | |
parent | 579571e05a08120133173933e7eaf2555846d1d7 (diff) | |
parent | 198b5cec531a8e0d6c121cc425e19a54b7818868 (diff) | |
download | dotty-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.scala | 83 |
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) |