diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index d097ed8dcc4e..4a06ee3ce07c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -196,7 +196,7 @@ 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 + // An inline unapply `P.unapply` in a pattern `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. // This serves as a placeholder for the inlined body until the `patternMatcher` phase. After pattern matcher @@ -210,18 +210,24 @@ object Inliner { val targs = fun match case TypeApply(_, targs) => targs + case Apply(TypeApply(_, targs), _) => targs case _ => Nil val unapplyInfo = sym.info match - case info: PolyType => info.instantiate(targs.map(_.tpe)) + case info: PolyType => info.instantiate(targs.map(_.tpe)) match + case MethodTpe(_, _, rt: PolyType) => rt.instantiate(targs.map(_.tpe)) + case MethodTpe(_, _, rt) if sym.flags.is(ExtensionMethod) => rt + case info => info + case MethodTpe(_, _, rt: PolyType) => rt.instantiate(targs.map(_.tpe)) + case MethodTpe(_, _, rt) if sym.flags.is(ExtensionMethod) => rt 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 => + inlineCall(fun.appliedToArgss(argss).withSpan(unapp.span))(using ctx.withOwner(unapplySym)) ) 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) cpy.UnApply(unapp)(newFun, implicits, patterns) } diff --git a/tests/pos/i8577/MacroA_1.scala b/tests/pos/i8577/MacroA_1.scala new file mode 100644 index 000000000000..1a147038adce --- /dev/null +++ b/tests/pos/i8577/MacroA_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroA: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyA(sc: Expr[MacroB.StringContext], input: Expr[Int]) + (using Quotes): Expr[Option[Seq[Int]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroB_1.scala b/tests/pos/i8577/MacroB_1.scala new file mode 100644 index 000000000000..e5b4ee5b5c66 --- /dev/null +++ b/tests/pos/i8577/MacroB_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroB: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyB[U](sc: Expr[MacroB.StringContext], input: Expr[U]) + (using Type[U])(using Quotes): Expr[Option[Seq[U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroC_1.scala b/tests/pos/i8577/MacroC_1.scala new file mode 100644 index 000000000000..be7047cb3527 --- /dev/null +++ b/tests/pos/i8577/MacroC_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroC: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyC[T](sc: Expr[MacroC.StringContext], input: Expr[T]) + (using Type[T])(using Quotes): Expr[Option[Seq[T]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroD_1.scala b/tests/pos/i8577/MacroD_1.scala new file mode 100644 index 000000000000..3e8d6df54484 --- /dev/null +++ b/tests/pos/i8577/MacroD_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroD: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyD[T](sc: Expr[MacroD.StringContext], input: Expr[T]) + (using Type[T])(using Quotes): Expr[Option[Seq[T]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroE_1.scala b/tests/pos/i8577/MacroE_1.scala new file mode 100644 index 000000000000..3351e3329c65 --- /dev/null +++ b/tests/pos/i8577/MacroE_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroE: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyE[T, U](sc: Expr[MacroE.StringContext], input: Expr[U]) + (using Type[U])(using Quotes): Expr[Option[Seq[U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroF_1.scala b/tests/pos/i8577/MacroF_1.scala new file mode 100644 index 000000000000..ebe01cbbacd7 --- /dev/null +++ b/tests/pos/i8577/MacroF_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroF: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyF[T, U](sc: Expr[MacroF.StringContext], input: Expr[(T, U)]) + (using Type[T], Type[U])(using Quotes): Expr[Option[Seq[(T, U)]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/MacroG_1.scala b/tests/pos/i8577/MacroG_1.scala new file mode 100644 index 000000000000..4324b553a7c1 --- /dev/null +++ b/tests/pos/i8577/MacroG_1.scala @@ -0,0 +1,12 @@ +package i8577 + +import scala.quoted._ + +object MacroG: + opaque type StringContext = scala.StringContext + def apply(ctx: scala.StringContext): StringContext = ctx + def unapply(ctx: StringContext): Option[scala.StringContext] = Some(ctx) + +def implUnapplyG[T, U](sc: Expr[MacroG.StringContext], input: Expr[T | U]) + (using Type[T], Type[U])(using Quotes): Expr[Option[Seq[T | U]]] = + '{ Some(Seq(${input})) } diff --git a/tests/pos/i8577/Main_2.scala b/tests/pos/i8577/Main_2.scala new file mode 100644 index 000000000000..43c818237689 --- /dev/null +++ b/tests/pos/i8577/Main_2.scala @@ -0,0 +1,164 @@ +package i8577 + +def main: Unit = { + { + extension (ctx: StringContext) def macroA: MacroB.StringContext = MacroB(ctx) + extension (inline ctx: MacroB.StringContext) inline def unapplySeq(inline input: Int): Option[Seq[Int]] = + ${implUnapplyA('ctx, 'input)} + + val macroA"$xA" = 1 + } + + { + extension (ctx: StringContext) def macroB: MacroB.StringContext = MacroB(ctx) + extension (inline ctx: MacroB.StringContext) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + ${ implUnapplyB('ctx, 'input) } + + val macroB"$xB" = 2 + } + + { + extension (ctx: StringContext) def macroC: MacroC.StringContext = MacroC(ctx) + extension [T] (inline ctx: MacroC.StringContext) inline def unapplySeq(inline input: T): Option[Seq[T]] = + ${ implUnapplyC('ctx, 'input) } + + val macroC"$xC" = 3 + } + + { + extension (ctx: StringContext) def macroD: MacroD.StringContext = MacroD(ctx) + extension [T] (inline ctx: MacroD.StringContext) inline def unapplySeq[U](inline input: T): Option[Seq[T]] = + ${ implUnapplyD('ctx, 'input) } + + // miscompilation +// val macroD"$xD" = 4 + } + + { + extension (ctx: StringContext) def macroE: MacroE.StringContext = MacroE(ctx) + extension [T] (inline ctx: MacroE.StringContext) inline def unapplySeq[U](inline input: U): Option[Seq[U]] = + ${ implUnapplyE('ctx, 'input) } + + val macroE"$xE" = 5 + } + + { + extension (ctx: StringContext) def macroF: MacroF.StringContext = MacroF(ctx) + extension [T] (inline ctx: MacroF.StringContext) inline def unapplySeq[U](inline input: (T, U)): Option[Seq[(T, U)]] = + ${ implUnapplyF('ctx, 'input) } + + val macroF"$xF" = (6, 7) + + // miscompilation +// val macroF"$xF" = (6, "7") + } + + { + extension (ctx: StringContext) def macroG: MacroG.StringContext = MacroG(ctx) + extension [T] (inline ctx: MacroG.StringContext) inline def unapplySeq[U](inline input: T | U): Option[Seq[T | U]] = + ${ implUnapplyG('ctx, 'input) } + + // compiler error +// val macroG"$xG" = 8 + } +} + +// { +// // B +// object F2 +// extension (o: F2.type) inline def unapplySeq[T](inline x: T) = Some(Seq(x)) +// +// val F2(x) = 16 +// println(s"F2: $x") +// } +// +// { +// // C +// object F1 +// extension [T] (o: F1.type) inline def unapplySeq(inline x: T) = Some(Seq(x)) +// +// val F1(x) = 15 +// println(s"F1: $x") +// } +// +// { +// // D +// object F4b +// extension [T] (o: F4b.type) inline def unapplySeq[U](inline x: T) = Some(Seq(x)) +// +// val F4b(x) = 18.2 +// println(s"F4b: $x") +// } +// +// { +// // E +// object F4b +// extension [T] (o: F4b.type) inline def unapplySeq[U](inline x: U) = Some(Seq(x)) +// +// val F4b(x) = 18.2 +// println(s"F4b: $x") +// } +// +// { +// // F +// object F4d +// extension [T] (o: F4d.type) inline def unapplySeq[U](inline x: (T, U)) = Some(Seq(x)) +// +// val F4d(x) = (18.4, 18.5) +// println(s"F4d: $x") +// } +// +// { +// // G +// object H1 +// extension (inline o: H1.type) inline def unapplySeq(inline x: Int) = Some(Seq(x)) +// +// val H1(x) = 23 +// println(s"H1: $x") +// } +// +// { +// // H +// object H2 +// extension (inline o: H2.type) inline def unapplySeq[T](inline x: T) = Some(Seq(x)) +// +// val H2(x) = 24 +// println(s"H2: $x") +// } +// +// { +// // I +// object H2 +// extension [T] (inline o: H2.type) inline def unapplySeq(inline x: T) = Some(Seq(x)) +// +// val H2(x) = 24 +// println(s"H2: $x") +// } +// +// { +// // J +// object H2 +// extension [T] (inline o: H2.type) inline def unapplySeq[U](inline x: T) = Some(Seq(x)) +// +// val H2(x) = 24 +// println(s"H2: $x") +// } +// +// { +// // K +// object H2 +// extension [T] (inline o: H2.type) inline def unapplySeq[U](inline x: U) = Some(Seq(x)) +// +// val H2(x) = 24 +// println(s"H2: $x") +// } +// +// { +// // L +// object H2 +// extension [T] (inline o: H2.type) inline def unapplySeq[U](inline x: (T, U)) = Some(Seq(x)) +// +// val H2(x) = (24, "a") +// println(s"H2: $x") +// } +//}