Skip to content

Commit 8547597

Browse files
committed
Fix scala#8530: Support inline unapply
1 parent b64b8a9 commit 8547597

File tree

5 files changed

+55
-6
lines changed

5 files changed

+55
-6
lines changed

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,10 +378,16 @@ object PatternMatcher {
378378
// This plan will never execute because it'll be guarded by a `NonNullTest`.
379379
ResultPlan(tpd.Throw(tpd.nullLiteral))
380380
else {
381-
val mt @ MethodType(_) = extractor.tpe.widen
382-
var unapp = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
383-
if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits)
384-
unapplyPlan(unapp, args)
381+
extractor.tpe.widen match
382+
case mt @ MethodType(_) =>
383+
var unapp = extractor.appliedTo(ref(scrutinee).ensureConforms(mt.paramInfos.head))
384+
if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits)
385+
unapplyPlan(unapp, args)
386+
case app: AppliedType =>
387+
// TODO optimize away the lambda
388+
var unapp = extractor.select(nme.apply).appliedTo(ref(scrutinee).ensureConforms(app.argInfos.head))
389+
if (implicits.nonEmpty) unapp = unapp.appliedToArgs(implicits)
390+
unapplyPlan(unapp, args)
385391
}
386392
if (scrutinee.info.isNotNull || nonNull(scrutinee)) unappPlan
387393
else TestPlan(NonNullTest, scrutinee, tree.span, unappPlan)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ 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)
244+
if (inlined.name == nme.unapplySeq) // TODO support
245245
ctx.error(em"Implementation restriction: inline ${inlined.name} methods are not supported", inlined.sourcePos)
246246

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

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,25 @@ class Typer extends Namer
12551255
if (bounds != null) sym.info = bounds
12561256
}
12571257
b
1258+
case t: UnApply if t.symbol.is(Inline) =>
1259+
def inlinedFun(lamTpe: MethodType, unappRef: Tree) = {
1260+
def body(scrutinee: Tree): Tree =
1261+
val call = unappRef.appliedTo(scrutinee).withSpan(t.span)
1262+
Inliner.inlineCall(call)
1263+
val fun = tpd.Lambda(lamTpe, args => body(args.head)).withSpan(t.span)
1264+
assert(t.implicits.isEmpty)
1265+
cpy.UnApply(t)(fun, t.implicits, t.patterns)
1266+
}
1267+
t.symbol.info match
1268+
case mt: MethodType =>
1269+
inlinedFun(mt, ref(t.symbol))
1270+
case mt: PolyType =>
1271+
val TypeApply(_, targs) = t.fun
1272+
val lamTpe = mt.resultType.substParams(mt, targs.map(_.tpe)).asInstanceOf[MethodType]
1273+
inlinedFun(lamTpe, ref(t.symbol).appliedToTypeTrees(targs))
1274+
case _ =>
1275+
ctx.error(em"Could not inline $t", t.sourcePos)
1276+
t
12581277
case t => t
12591278
}
12601279
}

tests/neg/inine-unnapply.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

22
object Foo {
3-
inline def unapply(x: Any): Boolean = ??? // error: Implementation restriction: inline unapply methods are not supported
3+
inline def unapply(x: Any): Boolean = ???
44
inline def unapplySeq(x: Any): Seq[Any] = ??? // error: Implementation restriction: inline unapplySeq methods are not supported
55
}

tests/pos/i8530.scala

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

0 commit comments

Comments
 (0)