diff options
author | Martin Odersky <odersky@gmail.com> | 2013-12-19 08:40:59 +0100 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-12-19 08:40:59 +0100 |
commit | 6be96724899f9c34db2e6c2617534dc9c4a15528 (patch) | |
tree | e396c405b43c6fc6f4fc8a124cb19acefb4dc755 /src/dotty/tools/dotc/typer/Applications.scala | |
parent | 56d8347bcd606443dde576480325677a89f5c809 (diff) | |
download | dotty-6be96724899f9c34db2e6c2617534dc9c4a15528.tar.gz dotty-6be96724899f9c34db2e6c2617534dc9c4a15528.tar.bz2 dotty-6be96724899f9c34db2e6c2617534dc9c4a15528.zip |
Following type aliases when pattern matching.
Faced with a pattern like
Apply(x, xs)
we first look for an Apply object which is an extractor. If this fails, we now
interprete Apply as a type. If it is a type alias which points to a class type that
has a companion module, we then try that companion module as an extractor.
Scala 2.x does ot that way, and it's used widely within dotty itself. Think tpd.Apply as the found object,
Trees.Apply as the extractor.
Also, added a fix to normalization which made normalization go deep into a method type.
Diffstat (limited to 'src/dotty/tools/dotc/typer/Applications.scala')
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 104fe0555..4202e05e1 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -333,7 +333,7 @@ trait Applications extends Compatibility { self: Typer => /** Subclass of Application for applicability tests with trees as arguments. */ class ApplicableToTrees(methRef: TermRef, args: List[Tree], resultType: Type)(implicit ctx: Context) extends TestApplication(methRef, methRef, args, resultType) { - def argType(arg: Tree): Type = normalize(arg.tpe) + def argType(arg: Tree): Type = normalize(arg.tpe, NoType) def treeToArg(arg: Tree): Tree = arg def isVarArg(arg: Tree): Boolean = tpd.isWildcardStarArg(arg) } @@ -546,7 +546,31 @@ trait Applications extends Compatibility { self: Typer => def notAnExtractor(tree: Tree) = errorTree(tree, s"${qual.show} cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method") - val unapply = { + /** If this is a term ref tree, try to typecheck with its type name. + * If this refers to a type alias, follow the alias, and if + * one finds a class, reference the class companion module. + */ + def followTypeAlias(tree: untpd.Tree): untpd.Tree = { + tree match { + case tree: untpd.RefTree => + val ttree = typedType(tree.withName(tree.name.toTypeName)) + ttree.tpe match { + case alias: TypeRef if alias.symbol.isAliasType => + companionRef(alias) match { + case companion: TermRef => return untpd.ref(companion) + case _ => + } + case _ => + } + case _ => + } + untpd.EmptyTree + } + + /** A typed qual.unappy or qual.unappySeq tree, if this typechecks. + * Otherwise fallBack with (maltyped) qual.unapply as argument + */ + def trySelectUnapply(qual: untpd.Tree)(fallBack: Tree => Tree): Tree = { val unappProto = new UnapplyFunProto(this) tryEither { implicit ctx => typedExpr(untpd.Select(qual, nme.unapply), unappProto) @@ -555,11 +579,20 @@ trait Applications extends Compatibility { self: Typer => tryEither { implicit ctx => typedExpr(untpd.Select(qual, nme.unapplySeq), unappProto) // for backwards compatibility; will be dropped } { - (_, _) => notAnExtractor(sel) + (_, _) => fallBack(sel) } } } + /** Produce a typed qual.unappy or qual.unappySeq tree, or + * else if this fails follow a type alias and try again. + */ + val unapply = trySelectUnapply(qual) { sel => + val qual1 = followTypeAlias(qual) + if (qual1.isEmpty) notAnExtractor(sel) + else trySelectUnapply(qual1)(_ => notAnExtractor(sel)) + } + def fromScala2x = unapply.symbol.exists && (unapply.symbol.owner is Scala2x) def unapplyArgs(unapplyResult: Type)(implicit ctx: Context): List[Type] = { |