From 3b1d78020683704fe65c58e7809851e33fda55fd Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 26 Jul 2021 16:45:24 +0200 Subject: [PATCH 1/2] Support inline unapply extension methods * Fixes the computation of the inline unapply temporary unanimous unapply placeholder * Handle leading given parameters in inline unapplies Fixes #8577 Fixes #12991 Fixes #15188 --- .../dotty/tools/dotc/inlines/Inlines.scala | 27 ++++++------------- tests/neg/i12991.scala | 7 ----- tests/pos-macros/i8577a/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577a/Main_2.scala | 9 +++++++ tests/pos-macros/i8577b/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577b/Main_2.scala | 9 +++++++ tests/pos-macros/i8577c/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577c/Main_2.scala | 9 +++++++ tests/pos-macros/i8577d/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577d/Main_2.scala | 9 +++++++ tests/pos-macros/i8577e/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577e/Main_2.scala | 9 +++++++ tests/pos-macros/i8577f/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577f/Main_2.scala | 12 +++++++++ tests/pos-macros/i8577g/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577g/Main_2.scala | 9 +++++++ tests/pos-macros/i8577h/Macro_1.scala | 11 ++++++++ tests/pos-macros/i8577h/Main_2.scala | 9 +++++++ tests/pos/i12991.scala | 15 +++++++++++ tests/pos/i15188.scala | 9 +++++++ tests/pos/i15188b.scala | 8 ++++++ tests/pos/i8577.scala | 21 +++++++++++++++ tests/run/i8577a.scala | 15 +++++++++++ tests/run/i8577b.scala | 15 +++++++++++ tests/run/i8577c.scala | 15 +++++++++++ tests/run/i8577d.scala | 15 +++++++++++ tests/run/i8577e.scala | 19 +++++++++++++ tests/run/i8577f.scala | 15 +++++++++++ tests/run/i8577g.scala | 15 +++++++++++ tests/run/i8577h.scala | 15 +++++++++++ tests/run/i8577i.scala | 16 +++++++++++ 31 files changed, 364 insertions(+), 26 deletions(-) delete mode 100644 tests/neg/i12991.scala create mode 100644 tests/pos-macros/i8577a/Macro_1.scala create mode 100644 tests/pos-macros/i8577a/Main_2.scala create mode 100644 tests/pos-macros/i8577b/Macro_1.scala create mode 100644 tests/pos-macros/i8577b/Main_2.scala create mode 100644 tests/pos-macros/i8577c/Macro_1.scala create mode 100644 tests/pos-macros/i8577c/Main_2.scala create mode 100644 tests/pos-macros/i8577d/Macro_1.scala create mode 100644 tests/pos-macros/i8577d/Main_2.scala create mode 100644 tests/pos-macros/i8577e/Macro_1.scala create mode 100644 tests/pos-macros/i8577e/Main_2.scala create mode 100644 tests/pos-macros/i8577f/Macro_1.scala create mode 100644 tests/pos-macros/i8577f/Main_2.scala create mode 100644 tests/pos-macros/i8577g/Macro_1.scala create mode 100644 tests/pos-macros/i8577g/Main_2.scala create mode 100644 tests/pos-macros/i8577h/Macro_1.scala create mode 100644 tests/pos-macros/i8577h/Main_2.scala create mode 100644 tests/pos/i12991.scala create mode 100644 tests/pos/i15188.scala create mode 100644 tests/pos/i15188b.scala create mode 100644 tests/pos/i8577.scala create mode 100644 tests/run/i8577a.scala create mode 100644 tests/run/i8577b.scala create mode 100644 tests/run/i8577c.scala create mode 100644 tests/run/i8577d.scala create mode 100644 tests/run/i8577e.scala create mode 100644 tests/run/i8577f.scala create mode 100644 tests/run/i8577g.scala create mode 100644 tests/run/i8577h.scala create mode 100644 tests/run/i8577i.scala diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index 9408ece0d4ac..b8d92b8a675a 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -181,35 +181,24 @@ object Inlines: // 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 ...)(x1,x2,...)(using t1: T1, t2: T2, ...)` is transformed into + // `{ class $anon { def unapply(s: S)(using t1: T1, t2: T2, ...): R = P.unapply[...](using ...)(s)(using t1, t2, ...) }; new $anon }.unapply(using y1,y2,...)` + // and the call `P.unapply[...](using ...)(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`. - 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, leadingImplicits), trailingImplicits, patterns) = unapp - if leadingImplicits.flatten.nonEmpty then - // To support them see https://github.com/lampepfl/dotty/pull/13158 - report.error("inline unapply methods with given parameters before the scrutinee are not supported", fun) + val UnApply(fun, trailingImplicits, patterns) = unapp val sym = unapp.symbol var unapplySym1: Symbol = NoSymbol // created from within AnonClass() and used afterwards val newUnapply = AnonClass(ctx.owner, List(defn.ObjectType), sym.coord) { cls => - val targs = fun match - case TypeApply(_, targs) => targs - case _ => Nil - val unapplyInfo = sym.info match - case info: PolyType => info.instantiate(targs.map(_.tpe)) - case info => info - - val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, unapplyInfo, coord = sym.coord).entered + // `fun` is a partially applied method that contains all type applications of the method. + // The methodic type `fun.tpe.widen` is the type of the function starting from the scrutinee argument + // and its type parameters are instantiated. + val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, fun.tpe.widen, coord = sym.coord).entered val unapply = DefDef(unapplySym.asTerm, argss => inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unapplySym)) ) diff --git a/tests/neg/i12991.scala b/tests/neg/i12991.scala deleted file mode 100644 index 90e037424c49..000000000000 --- a/tests/neg/i12991.scala +++ /dev/null @@ -1,7 +0,0 @@ -object Foo: - inline def unapply(using String)(i: Int): Some[Int] = Some(i) - -given String = "" - -val i = 10 match - case Foo(x) => x // error diff --git a/tests/pos-macros/i8577a/Macro_1.scala b/tests/pos-macros/i8577a/Macro_1.scala new file mode 100644 index 000000000000..3831f060f918 --- /dev/null +++ b/tests/pos-macros/i8577a/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply(sc: Expr[Macro.StrCtx], input: Expr[Int])(using Quotes): Expr[Option[Seq[Int]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577a/Main_2.scala b/tests/pos-macros/i8577a/Main_2.scala new file mode 100644 index 000000000000..5a0f6b609f81 --- /dev/null +++ b/tests/pos-macros/i8577a/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension (inline ctx: Macro.StrCtx) inline def unapplySeq(inline input: Int): Option[Seq[Int]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577b/Macro_1.scala b/tests/pos-macros/i8577b/Macro_1.scala new file mode 100644 index 000000000000..464d9894fa1c --- /dev/null +++ b/tests/pos-macros/i8577b/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[U](sc: Expr[Macro.StrCtx], input: Expr[U])(using Type[U])(using Quotes): Expr[Option[Seq[U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577b/Main_2.scala b/tests/pos-macros/i8577b/Main_2.scala new file mode 100644 index 000000000000..789e572bd5aa --- /dev/null +++ b/tests/pos-macros/i8577b/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577c/Macro_1.scala b/tests/pos-macros/i8577c/Macro_1.scala new file mode 100644 index 000000000000..45986b34d48d --- /dev/null +++ b/tests/pos-macros/i8577c/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T](sc: Expr[Macro.StrCtx], input: Expr[T])(using Type[T])(using Quotes): Expr[Option[Seq[T]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577c/Main_2.scala b/tests/pos-macros/i8577c/Main_2.scala new file mode 100644 index 000000000000..4f42c7635ec5 --- /dev/null +++ b/tests/pos-macros/i8577c/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq(inline input: T): Option[Seq[T]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577d/Macro_1.scala b/tests/pos-macros/i8577d/Macro_1.scala new file mode 100644 index 000000000000..45986b34d48d --- /dev/null +++ b/tests/pos-macros/i8577d/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T](sc: Expr[Macro.StrCtx], input: Expr[T])(using Type[T])(using Quotes): Expr[Option[Seq[T]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577d/Main_2.scala b/tests/pos-macros/i8577d/Main_2.scala new file mode 100644 index 000000000000..a87f06503b31 --- /dev/null +++ b/tests/pos-macros/i8577d/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: T): Option[Seq[T]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577e/Macro_1.scala b/tests/pos-macros/i8577e/Macro_1.scala new file mode 100644 index 000000000000..cf133d33a100 --- /dev/null +++ b/tests/pos-macros/i8577e/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T, U](sc: Expr[Macro.StrCtx], input: Expr[U])(using Type[U])(using Quotes): Expr[Option[Seq[U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577e/Main_2.scala b/tests/pos-macros/i8577e/Main_2.scala new file mode 100644 index 000000000000..598d18d2faec --- /dev/null +++ b/tests/pos-macros/i8577e/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577f/Macro_1.scala b/tests/pos-macros/i8577f/Macro_1.scala new file mode 100644 index 000000000000..7d3b5df28701 --- /dev/null +++ b/tests/pos-macros/i8577f/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T, U](sc: Expr[Macro.StrCtx], input: Expr[(T, U)])(using Type[T], Type[U])(using Quotes): Expr[Option[Seq[(T, U)]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577f/Main_2.scala b/tests/pos-macros/i8577f/Main_2.scala new file mode 100644 index 000000000000..fd1bb3e6186f --- /dev/null +++ b/tests/pos-macros/i8577f/Main_2.scala @@ -0,0 +1,12 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: (T, U)): Option[Seq[(T, U)]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = (1, 2) + assert(x == (1, 2)) + + val mac"$y" = (1, "a") + assert(y == (1, "a")) diff --git a/tests/pos-macros/i8577g/Macro_1.scala b/tests/pos-macros/i8577g/Macro_1.scala new file mode 100644 index 000000000000..2da12d6e23fd --- /dev/null +++ b/tests/pos-macros/i8577g/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T, U](sc: Expr[Macro.StrCtx], input: Expr[T | U])(using Type[T], Type[U])(using Quotes): Expr[Option[Seq[T | U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577g/Main_2.scala b/tests/pos-macros/i8577g/Main_2.scala new file mode 100644 index 000000000000..4998b9962802 --- /dev/null +++ b/tests/pos-macros/i8577g/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: T | U): Option[Seq[T | U]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) diff --git a/tests/pos-macros/i8577h/Macro_1.scala b/tests/pos-macros/i8577h/Macro_1.scala new file mode 100644 index 000000000000..2da12d6e23fd --- /dev/null +++ b/tests/pos-macros/i8577h/Macro_1.scala @@ -0,0 +1,11 @@ +package i8577 + +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def implUnapply[T, U](sc: Expr[Macro.StrCtx], input: Expr[T | U])(using Type[T], Type[U])(using Quotes): Expr[Option[Seq[T | U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos-macros/i8577h/Main_2.scala b/tests/pos-macros/i8577h/Main_2.scala new file mode 100644 index 000000000000..9fe2565a0ec3 --- /dev/null +++ b/tests/pos-macros/i8577h/Main_2.scala @@ -0,0 +1,9 @@ +package i8577 + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U | T): Option[Seq[T | U]] = + ${ implUnapply('ctx, 'input) } + + val mac"$x" = 1 + assert(x == 1) 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 diff --git a/tests/pos/i15188.scala b/tests/pos/i15188.scala new file mode 100644 index 000000000000..5dfdd5204faa --- /dev/null +++ b/tests/pos/i15188.scala @@ -0,0 +1,9 @@ +object O + +extension [T] (ctx: O.type) inline def unapplySeq(input: T): Option[Seq[T]] = Some(Seq(input)) + +@main +def Main = { + val O(x) = 3 + println(s"x: $x") +} diff --git a/tests/pos/i15188b.scala b/tests/pos/i15188b.scala new file mode 100644 index 000000000000..cdad3aff5099 --- /dev/null +++ b/tests/pos/i15188b.scala @@ -0,0 +1,8 @@ +class C + +extension (ctx: C) inline def unapply(input: String): Option[String] = Some("hi") + +@main def run = { + val O = new C + val O(x) = "3" +} diff --git a/tests/pos/i8577.scala b/tests/pos/i8577.scala new file mode 100644 index 000000000000..1f1a065ae5d1 --- /dev/null +++ b/tests/pos/i8577.scala @@ -0,0 +1,21 @@ +package i8577 + +type A; given A: A = ???; +type B; given B: B = ???; +type C; given C: C = ???; +type D; given D: D = ???; +type E; given E: E = ???; +type F; given F: F = ???; + + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +def main: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension [T] (using A)(inline ctx: Macro.StrCtx)(using B) inline def unapplySeq[U](using C)(inline input: T)(using D)(using F): Option[Seq[T]] = ??? + + (??? : Int) match + case mac"${x}" => 1 diff --git a/tests/run/i8577a.scala b/tests/run/i8577a.scala new file mode 100644 index 000000000000..fa9d23cb928a --- /dev/null +++ b/tests/run/i8577a.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension (inline ctx: Macro.StrCtx) inline def unapplySeq(inline input: Int): Option[Seq[Int]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577b.scala b/tests/run/i8577b.scala new file mode 100644 index 000000000000..91744cf48527 --- /dev/null +++ b/tests/run/i8577b.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577c.scala b/tests/run/i8577c.scala new file mode 100644 index 000000000000..e49743306ce4 --- /dev/null +++ b/tests/run/i8577c.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq(inline input: T): Option[Seq[T]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577d.scala b/tests/run/i8577d.scala new file mode 100644 index 000000000000..8af8fad7cd56 --- /dev/null +++ b/tests/run/i8577d.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: T): Option[Seq[T]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577e.scala b/tests/run/i8577e.scala new file mode 100644 index 000000000000..89d391ded2fd --- /dev/null +++ b/tests/run/i8577e.scala @@ -0,0 +1,19 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: (T, U)): Option[Seq[(T, U)]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = (1, 2) + val x2: (Int, Int) = x + assert(x == (1, 2)) + + val mac"$y" = (1, "a") + val y2: (Int, String) = y + assert(y == (1, "a")) diff --git a/tests/run/i8577f.scala b/tests/run/i8577f.scala new file mode 100644 index 000000000000..6ddaedc7b39f --- /dev/null +++ b/tests/run/i8577f.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +@main def Test: Unit = + extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) + extension (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + Some(Seq(input)) + + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577g.scala b/tests/run/i8577g.scala new file mode 100644 index 000000000000..ec5019d4c353 --- /dev/null +++ b/tests/run/i8577g.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: T | U): Option[Seq[T | U]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577h.scala b/tests/run/i8577h.scala new file mode 100644 index 000000000000..457c8138d840 --- /dev/null +++ b/tests/run/i8577h.scala @@ -0,0 +1,15 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension [T] (inline ctx: Macro.StrCtx) inline def unapplySeq[U](inline input: U | T): Option[Seq[T | U]] = + Some(Seq(input)) + +@main def Test: Unit = + val mac"$x" = 1 + val y: Int = x + assert(x == 1) diff --git a/tests/run/i8577i.scala b/tests/run/i8577i.scala new file mode 100644 index 000000000000..1893425b8782 --- /dev/null +++ b/tests/run/i8577i.scala @@ -0,0 +1,16 @@ +import scala.quoted._ + +object Macro: + opaque type StrCtx = StringContext + def apply(ctx: StringContext): StrCtx = ctx + def unapply(ctx: StrCtx): Option[StringContext] = Some(ctx) + +extension (ctx: StringContext) def mac: Macro.StrCtx = Macro(ctx) +extension (inline ctx: Macro.StrCtx) transparent inline def unapplySeq(inline input: String): Option[Seq[Any]] = + Some(Seq(123)) + +@main def Test: Unit = + "abc" match + case mac"$x" => + val y: Int = x + assert(x == 123) From 4fdb20cb12f8e65e431d9965ce54cc044329f027 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 7 Dec 2022 15:22:30 +0100 Subject: [PATCH 2/2] Only inline unapply methods in typer if is transparent --- compiler/src/dotty/tools/dotc/inlines/Inlines.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index b8d92b8a675a..ff08d551ca87 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -200,7 +200,9 @@ object Inlines: // and its type parameters are instantiated. val unapplySym = newSymbol(cls, sym.name.toTermName, Synthetic | Method, fun.tpe.widen, coord = sym.coord).entered val unapply = DefDef(unapplySym.asTerm, argss => - inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unapplySym)) + val body = fun.appliedToArgss(argss).withSpan(unapp.span) + if body.symbol.is(Transparent) then inlineCall(body)(using ctx.withOwner(unapplySym)) + else body ) unapplySym1 = unapplySym List(unapply)