|
| 1 | +package dotty.tools |
| 2 | +package dotc |
| 3 | +package transform |
| 4 | + |
| 5 | +import core._ |
| 6 | +import MegaPhase._ |
| 7 | +import Symbols._, Contexts._, Types._, Decorators._ |
| 8 | +import StdNames.nme |
| 9 | +import NameOps._ |
| 10 | +import Names._ |
| 11 | +import ast.Trees._ |
| 12 | +import ast.TreeTypeMap |
| 13 | + |
| 14 | +/** Rewrite an application |
| 15 | + * |
| 16 | + * {new { def unapply(x0: X0)(x1: X1,..., xn: Xn) = b }}.unapply(y0)(y1, ..., yn) |
| 17 | + * |
| 18 | + * where |
| 19 | + * |
| 20 | + * - the method is `unapply` or `unapplySeq` |
| 21 | + * - the method does not have type parameters |
| 22 | + * |
| 23 | + * to |
| 24 | + * |
| 25 | + * [xi := yi]b |
| 26 | + * |
| 27 | + * This removes placeholders added by inline `unapply`/`unapplySeq` patterns. |
| 28 | + */ |
| 29 | +class InlinePatterns extends MiniPhase: |
| 30 | + import ast.tpd._ |
| 31 | + |
| 32 | + def phaseName: String = "inlinePatterns" |
| 33 | + |
| 34 | + override def runsAfterGroupsOf: Set[String] = Set(PatternMatcher.name) |
| 35 | + |
| 36 | + override def transformApply(app: Apply)(using ctx: Context): Tree = |
| 37 | + if app.symbol.name.isUnapplyName && !app.tpe.isInstanceOf[MethodicType] then |
| 38 | + app match |
| 39 | + case App(Select(fn, name), argss) => |
| 40 | + val app1 = betaReduce(app, fn, name, argss.flatten) |
| 41 | + if app1 ne app then ctx.log(i"beta reduce $app -> $app1") |
| 42 | + app1 |
| 43 | + case _ => |
| 44 | + app |
| 45 | + else app |
| 46 | + |
| 47 | + private object App: |
| 48 | + def unapply(app: Tree): (Tree, List[List[Tree]]) = |
| 49 | + app match |
| 50 | + case Apply(App(fn, argss), args) => (fn, argss :+ args) |
| 51 | + case _ => (app, Nil) |
| 52 | + |
| 53 | + private def betaReduce(tree: Apply, fn: Tree, name: Name, args: List[Tree])(using ctx: Context): Tree = |
| 54 | + fn match |
| 55 | + case Block(Nil, expr) => betaReduce(tree, expr, name, args) |
| 56 | + case Block(TypeDef(_, template: Template) :: Nil, Apply(Select(New(_),_), Nil)) if template.constr.rhs.isEmpty => |
| 57 | + template.body match |
| 58 | + case List(ddef @ DefDef(`name`, _, _, _, _)) => |
| 59 | + val bindings = List.newBuilder[ValDef] |
| 60 | + val vparams = ddef.vparamss.flatten |
| 61 | + val argSyms = |
| 62 | + for (arg, param) <- args.zip(vparams) yield |
| 63 | + arg.tpe.dealias match |
| 64 | + case ref @ TermRef(NoPrefix, _) if isPurePath(arg) => |
| 65 | + ref.symbol |
| 66 | + case _ => |
| 67 | + val binding = SyntheticValDef(param.name, arg) |
| 68 | + bindings += binding |
| 69 | + binding.symbol |
| 70 | + seq( |
| 71 | + bindings.result(), |
| 72 | + TreeTypeMap( |
| 73 | + oldOwners = ddef.symbol :: Nil, |
| 74 | + newOwners = ctx.owner :: Nil, |
| 75 | + substFrom = vparams.map(_.symbol), |
| 76 | + substTo = argSyms).transform(ddef.rhs) |
| 77 | + ) |
| 78 | + |
| 79 | + case _ => tree |
| 80 | + case _ => tree |
0 commit comments