Skip to content

Commit

Permalink
Fix #8530: Support inline unapply
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Mar 13, 2020
1 parent ea27651 commit d857d94
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 7 deletions.
2 changes: 0 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/PrepareInlineable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,6 @@ object PrepareInlineable {
ctx.error(em"Implementation restriction: No inline methods allowed where opaque type aliases are in scope", inlined.sourcePos)
if (ctx.outer.inInlineMethod)
ctx.error(ex"Implementation restriction: nested inline methods are not supported", inlined.sourcePos)
if (inlined.name.isUnapplyName)
ctx.error(em"Implementation restriction: inline ${inlined.name} methods are not supported", inlined.sourcePos)

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

Expand Down
16 changes: 16 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,22 @@ class Typer extends Namer
if (bounds != null) sym.info = bounds
}
b
case t: UnApply if t.symbol.is(Inline) =>
val sym = t.symbol
val cls = ctx.newNormalizedClassSymbol(ctx.owner, tpnme.ANON_CLASS, Synthetic | Final, List(defn.ObjectType), coord = t.span)
val constr = ctx.newConstructor(cls, Synthetic, Nil, Nil).entered
val unappplySym = ctx.newSymbol(cls, sym.name.toTermName, Synthetic | Method, sym.info).entered
val unapply = polyDefDef(unappplySym, targs => argss =>
Inliner.inlineCall(ref(sym).appliedToTypes(targs).appliedToArgss(argss).withSpan(t.span))
)
val cdef = ClassDef(cls, DefDef(constr), List(unapply))
val newUnapply = Block(cdef :: Nil, New(cls.typeRef, Nil))
val targs = t.fun match
case TypeApply(_, targs) => targs
case _ => Nil
val newFun = newUnapply.select(unappplySym).appliedToTypeTrees(targs).withSpan(t.span)
assert(t.implicits.isEmpty)
cpy.UnApply(t)(newFun, t.implicits, t.patterns)
case t => t
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotc/pos-test-pickling.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ reference
scala-days-2019-slides
i7048e.scala
i8052.scala
i8530.scala

# Stale symbol: package object scala
seqtype-cycle
Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotc/run-test-pickling.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ t10889
macros-in-same-project1
i5257.scala
i7868.scala
i8530.scala
enum-java
zero-arity-case-class.scala
tuple-ops.scala
5 changes: 0 additions & 5 deletions tests/neg/inine-unnapply.scala

This file was deleted.

22 changes: 22 additions & 0 deletions tests/pos/i8530.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
object MyBoooleanUnapply:
inline def unapply(x: Int): Boolean = true

object MyOptionUnapply:
inline def unapply(x: Int): Option[Long] = Some(x)

object MyPolyUnapply:
inline def unapply[T](x: T): Option[T] = Some(x)

object MySeqUnapply:
inline def unapplySeq(x: Int): Seq[Int] = Seq(x, x)

object MyWhiteboxUnapply:
inline def unapply(x: Int) <: Option[Any] = Some(x)

def test =
5 match
case MyBoooleanUnapply() =>
case MyOptionUnapply(y) => println(y)
case MyPolyUnapply(a) =>
case MySeqUnapply(a, b) =>
case MyWhiteboxUnapply(x) => x: Int
5 changes: 5 additions & 0 deletions tests/pos/inine-unnapply.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

object Foo {
inline def unapply(x: Any): Boolean = ???
inline def unapplySeq(x: Any): Seq[Any] = ???
}
1 change: 1 addition & 0 deletions tests/run-macros/i8530-2.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
4 changes: 4 additions & 0 deletions tests/run-macros/i8530-2/App_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

@main def Test: Unit =
"foo" match
case xml"""<body>$linktext</body>""" => println(linktext)
15 changes: 15 additions & 0 deletions tests/run-macros/i8530-2/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import scala.quoted._

inline def (inline sc: StringContext).xml: XML = ${ impl('sc) }

trait XML:
def unapplySeq(xml: String): Option[Seq[String]]

private def impl(sc: Expr[StringContext])(using QuoteContext): Expr[XML] =
println("FIXME should only expand once per call site")
sc match
case '{ StringContext(${Varargs(Unlifted(args))}: _*)} => args
'{
new XML:
def unapplySeq(xml: String): Option[Seq[String]] = Some(Seq(xml))
}
12 changes: 12 additions & 0 deletions tests/run-macros/i8530/App_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

object Test {
def main(args: Array[String]): Unit = {
0 match
case Succ(n) => ???
case _ =>

2 match
case Succ(n) => assert(n == 1)
}

}
8 changes: 8 additions & 0 deletions tests/run-macros/i8530/Macro_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import scala.quoted._

object Succ:

inline def unapply(n: Int): Option[Int] = ${ impl('n) }

private def impl(n: Expr[Int])(using QuoteContext): Expr[Option[Int]] =
'{ if $n == 0 then None else Some($n - 1)}
5 changes: 5 additions & 0 deletions tests/run/i8530.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
MyBoooleanUnapply
2
3
(4,5)
5
33 changes: 33 additions & 0 deletions tests/run/i8530.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
object MyBoooleanUnapply:
inline def unapply(x: Int): Boolean = true

object MyOptionUnapply:
inline def unapply(x: Int): Option[Long] = Some(x)

object MyPolyUnapply:
inline def unapply[T](x: T): Option[T] = Some(x)

object MySeqUnapply:
inline def unapplySeq(x: Int): Seq[Int] = Seq(x, x + 1)

object MyWhiteboxUnapply:
inline def unapply(x: Int) <: Option[Any] = Some(x)


@main def Test =
1 match
case MyBoooleanUnapply() => println("MyBoooleanUnapply")

2 match
case MyOptionUnapply(y) => println(y)

3 match
case MyPolyUnapply(a) => println(a)

4 match
case MySeqUnapply(a, b) => println((a, b))

5 match
case MyWhiteboxUnapply(x) => println(x: Int)

end Test

0 comments on commit d857d94

Please sign in to comment.