Skip to content

Commit 4810559

Browse files
authored
Inline transparent implicit parameters when typing Unapply trees (#19646)
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 Fixes solution added in #19380
2 parents b18a02e + d244a30 commit 4810559

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

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

Lines changed: 12 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1492,7 +1492,7 @@ trait Applications extends Compatibility {
14921492

14931493
val dummyArg = dummyTreeOfType(ownType)
14941494
val (newUnapplyFn, unapplyApp) =
1495-
val unapplyAppCall = withMode(Mode.NoInline):
1495+
val unapplyAppCall =
14961496
typedExpr(untpd.TypedSplice(Apply(unapplyFn, dummyArg :: Nil)))
14971497
inlinedUnapplyFnAndApp(dummyArg, unapplyAppCall)
14981498

tests/pos/i19623.scala

Lines changed: 40 additions & 0 deletions
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)