Skip to content

Commit 2740927

Browse files
nicolasstuckiWojciechMazur
authored andcommitted
Inline transparent implicit parameters when typing Unapply trees
We needed to delay the inlining of the transparent inline when typing the unapply function application. We used the NoInline mode, but this also stopped the inlining of the arguments of the unapply. To fix this we target more precisely the inlining of the unapply method and not the implicit arguments. To do this we detect the dummy argument that is used type the unapply as an application, before it is transformed into a pattern. Fixes #19623 [Cherry-picked d244a30]
1 parent 60ecf4e commit 2740927

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

compiler/src/dotty/tools/dotc/inlines/Inlines.scala

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package inlines
55
import ast.*, core.*
66
import Flags.*, Symbols.*, Types.*, Decorators.*, Constants.*, Contexts.*
77
import StdNames.{tpnme, nme}
8+
import NameOps.*
89
import typer.*
910
import NameKinds.BodyRetainerName
1011
import SymDenotations.SymDenotation
@@ -54,6 +55,16 @@ object Inlines:
5455
def needsInlining(tree: Tree)(using Context): Boolean = tree match {
5556
case Block(_, expr) => needsInlining(expr)
5657
case _ =>
58+
def isUnapplyExpressionWithDummy: Boolean =
59+
// The first step of typing an `unapply` consists in typing the call
60+
// with a dummy argument (see Applications.typedUnApply). We delay the
61+
// inlining of this call.
62+
def rec(tree: Tree): Boolean = tree match
63+
case Apply(_, ProtoTypes.dummyTreeOfType(_) :: Nil) => true
64+
case Apply(fn, _) => rec(fn)
65+
case _ => false
66+
tree.symbol.name.isUnapplyName && rec(tree)
67+
5768
isInlineable(tree.symbol)
5869
&& !tree.tpe.widenTermRefExpr.isInstanceOf[MethodOrPoly]
5970
&& StagingLevel.level == 0
@@ -64,6 +75,7 @@ object Inlines:
6475
&& !ctx.typer.hasInliningErrors
6576
&& !ctx.base.stopInlining
6677
&& !ctx.mode.is(Mode.NoInline)
78+
&& !isUnapplyExpressionWithDummy
6779
}
6880

6981
private def needsTransparentInlining(tree: Tree)(using Context): Boolean =

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,7 @@ trait Applications extends Compatibility {
14761476

14771477
val dummyArg = dummyTreeOfType(ownType)
14781478
val (newUnapplyFn, unapplyApp) =
1479-
val unapplyAppCall = withMode(Mode.NoInline):
1479+
val unapplyAppCall =
14801480
typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil)))
14811481
inlinedUnapplyFnAndApp(dummyArg, unapplyAppCall)
14821482

tests/pos/i19623.scala

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import scala.compiletime.*
2+
import scala.language.dynamics
3+
4+
abstract class % extends Selectable
5+
6+
trait Select { type Out <: % }
7+
trait Selector extends Dynamic {
8+
def selectDynamic[S <: Singleton & String](label: S): Any = ???
9+
10+
def unapply[R: RecordLike](record: R)(using
11+
t: Select,
12+
r: RecordLike[t.Out]
13+
): r.ElemTypes = ???
14+
}
15+
16+
trait RecordLike[R] {
17+
type ElemTypes <: Tuple
18+
}
19+
20+
21+
@main def Test = {
22+
val r: %{ val name: String; } = ???
23+
24+
// originally derived in macro, use dummy instance instead
25+
transparent inline given outputRecordLike[R <: %]: RecordLike[R] = null.asInstanceOf[
26+
RecordLike[R] {
27+
type ElemTypes = String *: EmptyTuple
28+
}
29+
]
30+
31+
type FieldSelector = Select { type Out = % { val name: String } }
32+
given fieldSelector: FieldSelector = ???
33+
val selector: Selector = ???
34+
35+
val works = selector.unapply(r)
36+
val works2 = selector.unapply(r)(using summon, fieldSelector, summon)
37+
r match {
38+
case selector(value) => value // compilation error
39+
}
40+
}

0 commit comments

Comments
 (0)