@@ -124,6 +124,48 @@ object Inliner {
124124 )
125125 }
126126
127+ /** Try to inline a pattern with an inline unapply method. Fail with error if the maximal
128+ * inline depth is exceeded.
129+ *
130+ * @param unapp The tree of the pattern to inline
131+ * @return An `Unapply` with a `fun` containing the inlined call to the unapply
132+ */
133+ def inlinedUnapply (unapp : tpd.UnApply )(using ctx : Context ): Tree = {
134+ // We cannot inline the unapply directly, since the pattern matcher relies on unapply applications
135+ // as signposts what to do. On the other hand, we can do the inlining only in typer, not afterwards.
136+ // So the trick is to create a "wrapper" unapply in an anonymous class that has the inlined unapply
137+ // as its right hand side. The call to the wrapper unapply serves as the signpost for pattern matching.
138+ // After pattern matching, the anonymous class is removed in phase InlinePatterns with a beta reduction step.
139+ //
140+ // An inline unapply `P.unapply` in a plattern `P(x1,x2,...)` is transformed into
141+ // `{ class $anon { def unapply(t0: T0)(using t1: T1, t2: T2, ...): R = P.unapply(t0)(using t1, t2, ...) }; new $anon }.unapply`
142+ // and the call `P.unapply(x1, x2, ...)` is inlined.
143+ // This serves as a placeholder for the inlined body until the `patternMatcher` phase. After pattern matcher
144+ // transforms the patterns into terms, the `inlinePatterns` phase removes this anonymous class by β-reducing
145+ // the call to the `unapply`.
146+
147+ val UnApply (fun, implicits, patterns) = unapp
148+ val sym = unapp.symbol
149+ val cls = ctx.newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS , Synthetic | Final , List (defn.ObjectType ), coord = sym.coord)
150+ val constr = ctx.newConstructor(cls, Synthetic , Nil , Nil , coord = sym.coord).entered
151+
152+ val targs = fun match
153+ case TypeApply (_, targs) => targs
154+ case _ => Nil
155+ val unapplyInfo = sym.info match
156+ case info : PolyType => info.instantiate(targs.map(_.tpe))
157+ case info => info
158+
159+ val unappplySym = ctx.newSymbol(cls, sym.name.toTermName, Synthetic | Method , unapplyInfo, coord = sym.coord).entered
160+ val unapply = DefDef (unappplySym, argss =>
161+ inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(ctx.withOwner(unappplySym))
162+ )
163+ val cdef = ClassDef (cls, DefDef (constr), List (unapply))
164+ val newUnapply = Block (cdef :: Nil , New (cls.typeRef, Nil ))
165+ val newFun = newUnapply.select(unappplySym).withSpan(unapp.span)
166+ cpy.UnApply (unapp)(newFun, implicits, patterns)
167+ }
168+
127169 /** For a retained inline method, another method that keeps track of
128170 * the body that is kept at runtime. For instance, an inline method
129171 *
0 commit comments