@@ -124,6 +124,48 @@ object Inliner {
124
124
)
125
125
}
126
126
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
+
127
169
/** For a retained inline method, another method that keeps track of
128
170
* the body that is kept at runtime. For instance, an inline method
129
171
*
0 commit comments