From d3ff7924fd31f602968be3f8969c48dc55e99fcb Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 26 Jul 2021 16:45:24 +0200 Subject: [PATCH] Handle leading given parameters in inline unapplies Fixes #12991 --- .../src/dotty/tools/dotc/typer/Inliner.scala | 23 ++++++++++++------- tests/pos/i12991.scala | 15 ++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 tests/pos/i12991.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 722e3abfec85..9b84682cecab 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -190,14 +190,19 @@ object Inliner { // as its right hand side. The call to the wrapper unapply serves as the signpost for pattern matching. // After pattern matching, the anonymous class is removed in phase InlinePatterns with a beta reduction step. // - // An inline unapply `P.unapply` in a plattern `P(x1,x2,...)` is transformed into - // `{ class $anon { def unapply(t0: T0)(using t1: T1, t2: T2, ...): R = P.unapply(t0)(using t1, t2, ...) }; new $anon }.unapply` - // and the call `P.unapply(x1, x2, ...)` is inlined. + // An inline unapply `P.unapply` in a pattern `P(using y1,y2,...)(x1,x2,...)` is transformed into + // `{ class $anon { def unapply(using l1: L1, l2: L2, ...)(s: S)(using t1: T1, t2: T2, ...): R = P.unapply(using l1, l2, ...)(s)(using t1, t2, ...) }; new $anon }.unapply(using y1,y2,...)` + // and the call `P.unapply(using l1, l2,...)(x1, x2, ...)(using t1, t2, ...)` is inlined. // This serves as a placeholder for the inlined body until the `patternMatcher` phase. After pattern matcher // transforms the patterns into terms, the `inlinePatterns` phase removes this anonymous class by β-reducing // the call to the `unapply`. - val UnApply(fun, implicits, patterns) = unapp + object SplitFunAndGivenArgs: + def unapply(tree: Tree): (Tree, List[List[Tree]]) = tree match + case Apply(SplitFunAndGivenArgs(fn, argss), args) => (fn, argss :+ args) + case _ => (tree, Nil) + + val UnApply(SplitFunAndGivenArgs(fun, givenArgss) , implicits, patterns) = unapp val sym = unapp.symbol val cls = newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), newScope, coord = sym.coord) val constr = newConstructor(cls, Synthetic, Nil, Nil, coord = sym.coord).entered @@ -209,13 +214,15 @@ object Inliner { case info: PolyType => info.instantiate(targs.map(_.tpe)) case info => info - val unappplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered - val unapply = DefDef(unappplySym, argss => - inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unappplySym)) + val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered + val unapply = DefDef(unapplySym, argss => + fun.appliedToArgss(argss).withSpan(unapp.span) ) + val cdef = ClassDef(cls, DefDef(constr), List(unapply)) val newUnapply = Block(cdef :: Nil, New(cls.typeRef, Nil)) - val newFun = newUnapply.select(unappplySym).withSpan(unapp.span) + val newFun = newUnapply.select(unapplySym).withSpan(unapp.span).appliedToArgss(givenArgss) + cpy.UnApply(unapp)(newFun, implicits, patterns) } diff --git a/tests/pos/i12991.scala b/tests/pos/i12991.scala new file mode 100644 index 000000000000..4baaa048d67f --- /dev/null +++ b/tests/pos/i12991.scala @@ -0,0 +1,15 @@ +object Foo: + inline def unapply(using String)(i: Int): Some[Int] = Some(i) + +object Bar: + inline def unapply(using String)(using String)(i: Int): Some[Int] = Some(i) + +object Baz: + inline def unapply[T](using String)(i: T): Some[T] = Some(i) + +given String = "" + +val i = 10 match + case Foo(x) => x + case Bar(x) => x + case Baz(x) => x