From 146a362bf74418feeb18e12c34178819ecb64942 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 20 Dec 2013 11:33:05 +0100 Subject: Handling implicit unapply arguments. Changed format of UnApply nodes to also take implicit parameters. See doc comment in class Trees.UnApply --- src/dotty/tools/dotc/ast/CheckTrees.scala | 2 +- src/dotty/tools/dotc/ast/Trees.scala | 30 +++++++++++++++------- src/dotty/tools/dotc/ast/tpd.scala | 4 +-- src/dotty/tools/dotc/ast/untpd.scala | 2 +- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- src/dotty/tools/dotc/printing/RefinedPrinter.scala | 10 ++++++-- src/dotty/tools/dotc/typer/Applications.scala | 20 ++++++++++----- 7 files changed, 48 insertions(+), 22 deletions(-) (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/ast/CheckTrees.scala b/src/dotty/tools/dotc/ast/CheckTrees.scala index 56a8b9a88..6152a2880 100644 --- a/src/dotty/tools/dotc/ast/CheckTrees.scala +++ b/src/dotty/tools/dotc/ast/CheckTrees.scala @@ -195,7 +195,7 @@ object CheckTrees { } case Alternative(alts) => for (alt <- alts) check(alt.isValueOrPattern) - case UnApply(fun, args) => // todo: review + case UnApply(fun, implicits, args) => // todo: review check(fun.isTerm) for (arg <- args) check(arg.isValueOrPattern) val funtpe @ MethodType(_, _) = fun.tpe.widen diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 388cf8579..183e5a2e4 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -640,8 +640,20 @@ object Trees { type ThisTree[-T >: Untyped] = Alternative[T] } - /** fun(args) in a pattern, if fun is an extractor */ - case class UnApply[-T >: Untyped] private[ast] (fun: Tree[T], args: List[Tree[T]]) + /** The typed translation of `extractor(patterns)` in a pattern. The translation has the following + * components: + * + * @param fun is `extractor.unapply` (or, for backwards compatibility, `extractor.unapplySeq`) + * possibly with type parameters + * @param implicits Any implicit parameters passed to the unapply after the selector + * @param patterns The argument patterns in the pattern match. + * + * Given a match selector `sel` a pattern UnApply(fun, implicits, patterns) is roughly translated as follows + * + * val result = fun(sel)(implicits) + * if (result.isDefined) "match patterns against result" + */ + case class UnApply[-T >: Untyped] private[ast] (fun: Tree[T], implicits: List[Tree[T]], patterns: List[Tree[T]]) extends PatternTree[T] { type ThisTree[-T >: Untyped] = UnApply[T] } @@ -1014,9 +1026,9 @@ object Trees { case tree: Alternative if (trees eq tree.trees) => tree case _ => finalize(tree, untpd.Alternative(trees)) } - def UnApply(tree: Tree, fun: Tree, args: List[Tree]): UnApply = tree match { - case tree: UnApply if (fun eq tree.fun) && (args eq tree.args) => tree - case _ => finalize(tree, untpd.UnApply(fun, args)) + def UnApply(tree: Tree, fun: Tree, implicits: List[Tree], patterns: List[Tree]): UnApply = tree match { + case tree: UnApply if (fun eq tree.fun) && (implicits eq tree.implicits) && (patterns eq tree.patterns) => tree + case _ => finalize(tree, untpd.UnApply(fun, implicits, patterns)) } def ValDef(tree: Tree, mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = tree match { case tree: ValDef if (mods == tree.mods) && (name == tree.name) && (tpt eq tree.tpt) && (rhs eq tree.rhs) => tree @@ -1122,8 +1134,8 @@ object Trees { cpy.Bind(tree, name, transform(body)) case Alternative(trees) => cpy.Alternative(tree, transform(trees)) - case UnApply(fun, args) => - cpy.UnApply(tree, transform(fun), transform(args)) + case UnApply(fun, implicits, patterns) => + cpy.UnApply(tree, transform(fun), transform(implicits), transform(patterns)) case ValDef(mods, name, tpt, rhs) => cpy.ValDef(tree, mods, name, transform(tpt), transform(rhs)) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => @@ -1227,8 +1239,8 @@ object Trees { this(x, body) case Alternative(trees) => this(x, trees) - case UnApply(fun, args) => - this(this(x, fun), args) + case UnApply(fun, implicits, patterns) => + this(this(this(x, fun), implicits), patterns) case ValDef(mods, name, tpt, rhs) => this(this(x, tpt), rhs) case DefDef(mods, name, tparams, vparamss, tpt, rhs) => diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index 195797b2b..8d079fa72 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -205,12 +205,12 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def Alternative(trees: List[Tree])(implicit ctx: Context): Alternative = untpd.Alternative(trees).withType(ctx.typeComparer.lub(trees map (_.tpe))).checked - def UnApply(fun: Tree, args: List[Tree])(implicit ctx: Context): UnApply = { + def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree])(implicit ctx: Context): UnApply = { val owntype = fun.tpe.widen match { case MethodType(_, paramType :: Nil) => paramType case _ => check(false); ErrorType } - untpd.UnApply(fun, args).withType(owntype).checked + untpd.UnApply(fun, implicits, patterns).withType(owntype).checked } def ValDef(sym: TermSymbol, rhs: Tree = EmptyTree)(implicit ctx: Context): ValDef = diff --git a/src/dotty/tools/dotc/ast/untpd.scala b/src/dotty/tools/dotc/ast/untpd.scala index 740e8f110..afb3ba63a 100644 --- a/src/dotty/tools/dotc/ast/untpd.scala +++ b/src/dotty/tools/dotc/ast/untpd.scala @@ -82,7 +82,7 @@ object untpd extends Trees.Instance[Untyped] with TreeInfo[Untyped] { def TypeBoundsTree(lo: Tree, hi: Tree): TypeBoundsTree = new TypeBoundsTree(lo, hi) def Bind(name: Name, body: Tree): Bind = new Bind(name, body) def Alternative(trees: List[Tree]): Alternative = new Alternative(trees) - def UnApply(fun: Tree, args: List[Tree]): UnApply = new UnApply(fun, args) + def UnApply(fun: Tree, implicits: List[Tree], patterns: List[Tree]): UnApply = new UnApply(fun, implicits, patterns) def ValDef(mods: Modifiers, name: TermName, tpt: Tree, rhs: Tree): ValDef = new ValDef(mods, name, tpt, rhs) def DefDef(mods: Modifiers, name: TermName, tparams: List[TypeDef], vparamss: List[List[ValDef]], tpt: Tree, rhs: Tree): DefDef = new DefDef(mods, name, tparams, vparamss, tpt, rhs) def TypeDef(mods: Modifiers, name: TypeName, rhs: Tree): TypeDef = new TypeDef(mods, name, rhs) diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index 88dbca4f7..177a8f21d 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -979,7 +979,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClassRoot: case UNAPPLYtree => val fun = readTreeRef() val args = until(end, readTreeRef) - UnApply(fun, args) + UnApply(fun, Nil, args) // !!! this is wrong in general case ARRAYVALUEtree => val elemtpt = readTreeRef() diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala index b4221d7eb..3636731aa 100644 --- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -241,8 +241,14 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { changePrec(InfixPrec) { toText(name) ~ " @ " ~ toText(body) } case Alternative(trees) => changePrec(OrPrec) { toText(trees, " | ") } - case UnApply(fun, args) => - toTextLocal(fun) ~ "(" ~ toTextGlobal(args, ", ") ~ ")" + case UnApply(fun, implicits, patterns) => + val extractor = fun match { + case Select(extractor, nme.unapply) => extractor + case _ => fun + } + toTextLocal(extractor) ~ + "(" ~ toTextGlobal(patterns, ", ") ~ ")" ~ + ("(" ~ toTextGlobal(implicits, ", ") ~ ")" provided implicits.nonEmpty) case ValDef(mods, name, tpt, rhs) => modText(mods, if (mods is Mutable) "var" else "val") ~~ toText(name) ~ optAscription(tpt) ~ optText(rhs)(" = " ~ _) diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index ad6bdd787..08987a095 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -629,7 +629,7 @@ trait Applications extends Compatibility { self: Typer => } unapply.tpe.widen match { - case mt: MethodType if !mt.isDependent => + case mt: MethodType if mt.paramTypes.length == 1 && !mt.isDependent => val unapplyArgType = mt.paramTypes.head println(s"unapp arg tpe = ${unapplyArgType.show}, pt = ${pt.show}") def wpt = widenForMatchSelector(pt) @@ -671,7 +671,15 @@ trait Applications extends Compatibility { self: Typer => i"Pattern type $unapplyArgType is neither a subtype nor a supertype of selector type $wpt", tree.pos) } - var argTypes = unapplyArgs(mt.resultType) + + val dummyArg = dummyTreeOfType(unapplyArgType) + val unapplyApp = typedExpr(untpd.TypedSplice(Apply(unapply, dummyArg :: Nil))) + val unapplyImplicits = unapplyApp match { + case Apply(Apply(unapply, `dummyArg` :: Nil), args2) => assert(args2.nonEmpty); args2 + case Apply(unapply, `dummyArg` :: Nil) => Nil + } + + var argTypes = unapplyArgs(unapplyApp.tpe) val bunchedArgs = argTypes match { case argType :: Nil if argType.isRepeatedParam => untpd.SeqLiteral(args) :: Nil case _ => args @@ -681,15 +689,15 @@ trait Applications extends Compatibility { self: Typer => argTypes = argTypes.take(args.length) ++ List.fill(argTypes.length - args.length)(WildcardType) } - val typedArgs = (bunchedArgs, argTypes).zipped map (typed(_, _)) - val result = cpy.UnApply(tree, unapply, typedArgs) withType ownType - println(s"typedargs = $typedArgs") + val unapplyPatterns = (bunchedArgs, argTypes).zipped map (typed(_, _)) + val result = cpy.UnApply(tree, unapply, unapplyImplicits, unapplyPatterns) withType ownType + println(s"unapply patterns = $unapplyPatterns") if ((ownType eq pt) || ownType.isError) result else Typed(result, TypeTree(ownType)) case tp => val unapplyErr = if (tp.isError) unapply else notAnExtractor(unapply) val typedArgsErr = args mapconserve (typed(_, defn.AnyType)) - cpy.UnApply(tree, unapplyErr, typedArgsErr) withType ErrorType + cpy.UnApply(tree, unapplyErr, Nil, typedArgsErr) withType ErrorType } } -- cgit v1.2.3