From b1553cb9c5894e2e91925a67afd2c986675e5c46 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 15 Dec 2016 15:21:26 +0100 Subject: Implement new rules for name-based pattern matching This implements the rules laid down in #1805. --- .../src/dotty/tools/dotc/typer/Applications.scala | 44 +++++++++++++--------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'compiler/src/dotty/tools/dotc/typer/Applications.scala') diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index eca4df617..d34804865 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -47,13 +47,13 @@ object Applications { ref.info.widenExpr.dealias } - /** Does `tp` fit the "product match" conditions as an unapply result type? - * This is the case of `tp` is a subtype of a ProductN class and `tp` has a - * parameterless `isDefined` member of result type `Boolean`. + /** Does `tp` fit the "product match" conditions as an unapply result type + * for a pattern with `numArgs` subpatterns> + * This is the case of `tp` is a subtype of the Product class. */ - def isProductMatch(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context) = - extractorMemberType(tp, nme.isDefined, errorPos).isRef(defn.BooleanClass) && - defn.isProductSubType(tp) + def isProductMatch(tp: Type, numArgs: Int)(implicit ctx: Context) = + 0 <= numArgs && numArgs <= Definitions.MaxTupleArity && + tp.derivesFrom(defn.ProductNType(numArgs).typeSymbol) /** Does `tp` fit the "get match" conditions as an unapply result type? * This is the case of `tp` has a `get` member as well as a @@ -82,28 +82,38 @@ object Applications { def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = { + val unapplyName = unapplyFn.symbol.name def seqSelector = defn.RepeatedParamType.appliedTo(unapplyResult.elemType :: Nil) + def getTp = extractorMemberType(unapplyResult, nme.get, pos) def fail = { - ctx.error(i"$unapplyResult is not a valid result type of an unapply method of an extractor", pos) + ctx.error(i"$unapplyResult is not a valid result type of an $unapplyName method of an extractor", pos) Nil } - // println(s"unapply $unapplyResult ${extractorMemberType(unapplyResult, nme.isDefined)}") - if (isProductMatch(unapplyResult)) - productSelectorTypes(unapplyResult) - else if (isGetMatch(unapplyResult)) { - val getTp = extractorMemberType(unapplyResult, nme.get, pos) - if (unapplyFn.symbol.name == nme.unapplySeq) { + if (unapplyName == nme.unapplySeq) { + if (unapplyResult derivesFrom defn.SeqClass) seqSelector :: Nil + else if (isGetMatch(unapplyResult, pos)) { val seqArg = boundsToHi(getTp.elemType) if (seqArg.exists) args.map(Function.const(seqArg)) else fail } - else getUnapplySelectors(getTp, args, pos) + else fail + } + else { + assert(unapplyName == nme.unapply) + if (isProductMatch(unapplyResult, args.length)) + productSelectorTypes(unapplyResult) + else if (isGetMatch(unapplyResult, pos)) + getUnapplySelectors(getTp, args, pos) + else if (unapplyResult isRef defn.BooleanClass) + Nil + else if (defn.isProductSubType(unapplyResult)) + productSelectorTypes(unapplyResult) + // this will cause a "wrong number of arguments in pattern" error later on, + // which is better than the message in `fail`. + else fail } - else if (unapplyResult derivesFrom defn.SeqClass) seqSelector :: Nil - else if (unapplyResult isRef defn.BooleanClass) Nil - else fail } def wrapDefs(defs: mutable.ListBuffer[Tree], tree: Tree)(implicit ctx: Context): Tree = -- cgit v1.2.3