Skip to content

Commit beca150

Browse files
committed
Fix inlining of right-associative transparent methods
The stricter rules that transparent methods must be inlined revealed that right-associative curried methods such as /: were never inlined. To fix this: - take Blocks into account when deciding whether a tree is inlineable - fix typedApply, so that Blocks are moved outwards over curried applications - fix inlineCall so that we inline inside a block
1 parent 0b7710a commit beca150

File tree

3 files changed

+46
-30
lines changed

3 files changed

+46
-30
lines changed

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

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
738738
}
739739

740740
fun1.tpe match {
741-
case err: ErrorType => untpd.cpy.Apply(tree)(fun1, proto.typedArgs).withType(err)
741+
case err: ErrorType => cpy.Apply(tree)(fun1, proto.typedArgs).withType(err)
742742
case TryDynamicCallType => typedDynamicApply(tree, pt)
743743
case _ =>
744744
if (originalProto.isDropped) fun1
@@ -777,27 +777,34 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
777777
wrapDefs(liftedDefs, typed(assign))
778778
}
779779

780-
if (untpd.isOpAssign(tree))
781-
tryEither {
782-
implicit ctx => realApply
783-
} { (failedVal, failedState) =>
780+
val app1 =
781+
if (untpd.isOpAssign(tree))
784782
tryEither {
785-
implicit ctx => typedOpAssign
786-
} { (_, _) =>
787-
failedState.commit()
788-
failedVal
783+
implicit ctx => realApply
784+
} { (failedVal, failedState) =>
785+
tryEither {
786+
implicit ctx => typedOpAssign
787+
} { (_, _) =>
788+
failedState.commit()
789+
failedVal
790+
}
789791
}
792+
else {
793+
val app = realApply
794+
app match {
795+
case Apply(fn @ Select(left, _), right :: Nil) if fn.hasType =>
796+
val op = fn.symbol
797+
if (op == defn.Any_== || op == defn.Any_!=)
798+
checkCanEqual(left.tpe.widen, right.tpe.widen, app.pos)
799+
case _ =>
800+
}
801+
app
790802
}
791-
else {
792-
val app = realApply
793-
app match {
794-
case Apply(fn @ Select(left, _), right :: Nil) if fn.hasType =>
795-
val op = fn.symbol
796-
if (op == defn.Any_== || op == defn.Any_!=)
797-
checkCanEqual(left.tpe.widen, right.tpe.widen, app.pos)
798-
case _ =>
799-
}
800-
app
803+
app1 match {
804+
case Apply(Block(stats, fn), args) =>
805+
tpd.cpy.Block(app1)(stats, tpd.cpy.Apply(app1)(fn, args))
806+
case _ =>
807+
app1
801808
}
802809
}
803810

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ object Inliner {
6767
hasBodyToInline(meth) && !suppressInline
6868
}
6969

70+
/** Should call be inlined in this context? */
71+
def isInlineable(tree: Tree)(implicit ctx: Context): Boolean = tree match {
72+
case Block(_, expr) => isInlineable(expr)
73+
case _ => isInlineable(tree.symbol)
74+
}
75+
7076
/** Is `meth` a transparent method that should be inlined in this context? */
7177
def isTransparentInlineable(meth: Symbol)(implicit ctx: Context): Boolean =
7278
meth.isTransparentInlineable && isInlineable(meth)
@@ -79,8 +85,10 @@ object Inliner {
7985
* @return An `Inlined` node that refers to the original call and the inlined bindings
8086
* and body that replace it.
8187
*/
82-
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree =
83-
if (enclosingInlineds.length < ctx.settings.XmaxInlines.value) {
88+
def inlineCall(tree: Tree, pt: Type)(implicit ctx: Context): Tree = tree match {
89+
case Block(stats, expr) =>
90+
cpy.Block(tree)(stats, inlineCall(expr, pt))
91+
case _ if (enclosingInlineds.length < ctx.settings.XmaxInlines.value) =>
8492
val body = bodyToInline(tree.symbol) // can typecheck the tree and thereby produce errors
8593
if (ctx.reporter.hasErrors) tree
8694
else {
@@ -89,14 +97,15 @@ object Inliner {
8997
else ctx.fresh.setProperty(InlineBindings, newMutableSymbolMap[Tree])
9098
new Inliner(tree, body)(inlinerCtx).inlined(pt)
9199
}
92-
}
93-
else errorTree(
94-
tree,
95-
i"""|Maximal number of successive inlines (${ctx.settings.XmaxInlines.value}) exceeded,
96-
|Maybe this is caused by a recursive transparent method?
97-
|You can use -Xmax:inlines to change the limit.""",
98-
(tree :: enclosingInlineds).last.pos
99-
)
100+
case _ =>
101+
errorTree(
102+
tree,
103+
i"""|Maximal number of successive inlines (${ctx.settings.XmaxInlines.value}) exceeded,
104+
|Maybe this is caused by a recursive transparent method?
105+
|You can use -Xmax:inlines to change the limit.""",
106+
(tree :: enclosingInlineds).last.pos
107+
)
108+
}
100109

101110
/** Replace `Inlined` node by a block that contains its bindings and expansion */
102111
def dropInlined(inlined: tpd.Inlined)(implicit ctx: Context): Tree = {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2378,7 +2378,7 @@ class Typer extends Namer
23782378
checkEqualityEvidence(tree, pt)
23792379
tree
23802380
}
2381-
else if (Inliner.isInlineable(tree.symbol)) {
2381+
else if (Inliner.isInlineable(tree)) {
23822382
tree.tpe <:< wildApprox(pt)
23832383
readaptSimplified(Inliner.inlineCall(tree, pt))
23842384
}

0 commit comments

Comments
 (0)