Skip to content

Commit 3f3a3da

Browse files
committed
Fix #8530: Support inline unapply
1 parent ea27651 commit 3f3a3da

14 files changed

+122
-22
lines changed

compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,6 @@ object PrepareInlineable {
241241
ctx.error(em"Implementation restriction: No inline methods allowed where opaque type aliases are in scope", inlined.sourcePos)
242242
if (ctx.outer.inInlineMethod)
243243
ctx.error(ex"Implementation restriction: nested inline methods are not supported", inlined.sourcePos)
244-
if (inlined.name.isUnapplyName)
245-
ctx.error(em"Implementation restriction: inline ${inlined.name} methods are not supported", inlined.sourcePos)
246244

247245
if (inlined.is(Macro) && !ctx.isAfterTyper) {
248246

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,21 @@ class Typer extends Namer
12551255
if (bounds != null) sym.info = bounds
12561256
}
12571257
b
1258+
case t: UnApply if t.symbol.is(Inline) =>
1259+
val sym = t.symbol
1260+
val cls = ctx.newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), coord = t.span)
1261+
val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered
1262+
val unappplySym = ctx.newSymbol(cls, sym.name.toTermName, Synthetic | Method, sym.info).entered
1263+
val unapply = polyDefDef(unappplySym, targs => argss =>
1264+
Inliner.inlineCall(ref(sym).appliedToTypes(targs).appliedToArgss(argss).withSpan(t.span))
1265+
)
1266+
val cdef = ClassDef(cls, DefDef(constr), List(unapply))
1267+
val newUnapply = Block(cdef :: Nil, New(cls.typeRef, Nil))
1268+
val targs = t.fun match
1269+
case TypeApply(_, targs) => targs
1270+
case _ => Nil
1271+
val newFun = newUnapply.select(unappplySym).appliedToTypeTrees(targs).withSpan(t.span)
1272+
cpy.UnApply(t)(newFun, t.implicits, t.patterns)
12581273
case t => t
12591274
}
12601275
}

compiler/test/dotc/pos-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ reference
1212
scala-days-2019-slides
1313
i7048e.scala
1414
i8052.scala
15+
i8530.scala
1516

1617
# Stale symbol: package object scala
1718
seqtype-cycle

compiler/test/dotc/run-test-pickling.blacklist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ t10889
2323
macros-in-same-project1
2424
i5257.scala
2525
i7868.scala
26+
i8530.scala
2627
enum-java
2728
zero-arity-case-class.scala
2829
tuple-ops.scala

tests/neg/inine-unnapply.scala

Lines changed: 0 additions & 5 deletions
This file was deleted.

tests/neg/inline-unapply.scala

Lines changed: 0 additions & 15 deletions
This file was deleted.

tests/pos/i8530.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
object MyBoooleanUnapply:
2+
inline def unapply(x: Int): Boolean = true
3+
4+
object MyOptionUnapply:
5+
inline def unapply(x: Int): Option[Long] = Some(x)
6+
7+
object MyUnapplyImplicits:
8+
inline def unapply(x: Int)(using DummyImplicit): Option[Long] = Some(x)
9+
10+
object MyPolyUnapply:
11+
inline def unapply[T](x: T): Option[T] = Some(x)
12+
13+
object MySeqUnapply:
14+
inline def unapplySeq(x: Int): Seq[Int] = Seq(x, x)
15+
16+
object MyWhiteboxUnapply:
17+
inline def unapply(x: Int) <: Option[Any] = Some(x)
18+
19+
def test: Unit =
20+
val x = 5 match
21+
case MyBoooleanUnapply() =>
22+
case MyOptionUnapply(y) => y: Long
23+
case MyUnapplyImplicits(y) => y: Long
24+
case MyPolyUnapply(a) => a: Int
25+
case MySeqUnapply(a, b) => (a: Int, b: Int)
26+
case MyWhiteboxUnapply(x) => x: Int

tests/pos/inine-unnapply.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
object Foo {
3+
inline def unapply(x: Any): Boolean = ???
4+
inline def unapplySeq(x: Any): Seq[Any] = ???
5+
}

tests/pos/inline-unapply.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
object Test {
2+
3+
class C(val x: Int, val y: Int)
4+
5+
inline def unapply(c: C): Some[(Int, Int)] = Some((c.x, c.y))
6+
7+
}
8+
object Test2 {
9+
10+
class C(x: Int, y: Int)
11+
12+
inline def unapply(c: C): Option[(Int, Int)] = inline c match {
13+
case x: C => Some((1, 1))
14+
}
15+
}

tests/run-macros/i8530-2.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
foo

tests/run-macros/i8530/App_2.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
object Test {
3+
def main(args: Array[String]): Unit = {
4+
0 match
5+
case Succ(n) => ???
6+
case _ =>
7+
8+
2 match
9+
case Succ(n) => assert(n == 1)
10+
}
11+
12+
}

tests/run-macros/i8530/Macro_1.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import scala.quoted._
2+
3+
object Succ:
4+
5+
inline def unapply(n: Int): Option[Int] = ${ impl('n) }
6+
7+
private def impl(n: Expr[Int])(using QuoteContext): Expr[Option[Int]] =
8+
'{ if $n == 0 then None else Some($n - 1)}

tests/run/i8530.check

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
MyBoooleanUnapply
2+
2
3+
3
4+
(4,5)
5+
5

tests/run/i8530.scala

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
object MyBoooleanUnapply:
2+
inline def unapply(x: Int): Boolean = true
3+
4+
object MyOptionUnapply:
5+
inline def unapply(x: Int): Option[Long] = Some(x)
6+
7+
object MyPolyUnapply:
8+
inline def unapply[T](x: T): Option[T] = Some(x)
9+
10+
object MySeqUnapply:
11+
inline def unapplySeq(x: Int): Seq[Int] = Seq(x, x + 1)
12+
13+
object MyWhiteboxUnapply:
14+
inline def unapply(x: Int) <: Option[Any] = Some(x)
15+
16+
17+
@main def Test =
18+
1 match
19+
case MyBoooleanUnapply() => println("MyBoooleanUnapply")
20+
21+
2 match
22+
case MyOptionUnapply(y) => println(y)
23+
24+
3 match
25+
case MyPolyUnapply(a) => println(a)
26+
27+
4 match
28+
case MySeqUnapply(a, b) => println((a, b))
29+
30+
5 match
31+
case MyWhiteboxUnapply(x) => println(x: Int)
32+
33+
end Test

0 commit comments

Comments
 (0)