| 
 | 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