diff options
author | Martin Odersky <odersky@gmail.com> | 2016-12-14 22:21:51 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-12-14 23:27:05 +0100 |
commit | 9bf58090c704a59d8735874c565200758bcea666 (patch) | |
tree | 705c77dc8cea85ecf0203ea710957542541c4bb5 /compiler/src/dotty/tools/dotc/typer | |
parent | ba06bf06721f1a8de7d68d22ad7eba27fff90c43 (diff) | |
download | dotty-9bf58090c704a59d8735874c565200758bcea666.tar.gz dotty-9bf58090c704a59d8735874c565200758bcea666.tar.bz2 dotty-9bf58090c704a59d8735874c565200758bcea666.zip |
Change by-name pattern matching.
New implementation following the scheme outlined in #1790.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/typer')
-rw-r--r-- | compiler/src/dotty/tools/dotc/typer/Applications.scala | 62 |
1 files changed, 43 insertions, 19 deletions
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 11121e1f3..eca4df617 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -32,16 +32,37 @@ import reporting.diagnostic.Message object Applications { import tpd._ + def extractorMember(tp: Type, name: Name)(implicit ctx: Context) = { + def isPossibleExtractorType(tp: Type) = tp match { + case _: MethodType | _: PolyType => false + case _ => true + } + tp.member(name).suchThat(d => isPossibleExtractorType(d.info)) + } + def extractorMemberType(tp: Type, name: Name, errorPos: Position = NoPosition)(implicit ctx: Context) = { - val ref = tp.member(name).suchThat(_.info.isParameterless) + val ref = extractorMember(tp, name) if (ref.isOverloaded) errorType(i"Overloaded reference to $ref is not allowed in extractor", errorPos) - else if (ref.info.isInstanceOf[PolyType]) - errorType(i"Reference to polymorphic $ref: ${ref.info} is not allowed in extractor", errorPos) - else - ref.info.widenExpr.dealias + 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`. + */ + def isProductMatch(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context) = + extractorMemberType(tp, nme.isDefined, errorPos).isRef(defn.BooleanClass) && + defn.isProductSubType(tp) + + /** 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 + * parameterless `isDefined` member of result type `Boolean`. + */ + def isGetMatch(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context) = + extractorMemberType(tp, nme.isEmpty, errorPos).isRef(defn.BooleanClass) && + extractorMemberType(tp, nme.get, errorPos).exists + def productSelectorTypes(tp: Type, errorPos: Position = NoPosition)(implicit ctx: Context): List[Type] = { val sels = for (n <- Iterator.from(0)) yield extractorMemberType(tp, nme.selectorName(n), errorPos) sels.takeWhile(_.exists).toList @@ -62,24 +83,27 @@ object Applications { def unapplyArgs(unapplyResult: Type, unapplyFn: Tree, args: List[untpd.Tree], pos: Position = NoPosition)(implicit ctx: Context): List[Type] = { def seqSelector = defn.RepeatedParamType.appliedTo(unapplyResult.elemType :: Nil) - def getTp = extractorMemberType(unapplyResult, nme.get, pos) - // println(s"unapply $unapplyResult ${extractorMemberType(unapplyResult, nme.isDefined)}") - if (extractorMemberType(unapplyResult, nme.isDefined, pos) isRef defn.BooleanClass) { - if (getTp.exists) - if (unapplyFn.symbol.name == nme.unapplySeq) { - val seqArg = boundsToHi(getTp.elemType) - if (seqArg.exists) return args map Function.const(seqArg) - } - else return getUnapplySelectors(getTp, args, pos) - else if (defn.isProductSubType(unapplyResult)) return productSelectorTypes(unapplyResult, pos) - } - if (unapplyResult derivesFrom defn.SeqClass) seqSelector :: Nil - else if (unapplyResult isRef defn.BooleanClass) Nil - else { + def fail = { ctx.error(i"$unapplyResult is not a valid result type of an unapply 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) { + val seqArg = boundsToHi(getTp.elemType) + if (seqArg.exists) args.map(Function.const(seqArg)) + else fail + } + else getUnapplySelectors(getTp, args, pos) + } + 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 = |