Skip to content

Commit f25d48d

Browse files
committed
Prepare to have both inlined and transparent methods
All necessary changes except for those in the Inliner itself.
1 parent 62a5707 commit f25d48d

File tree

9 files changed

+62
-30
lines changed

9 files changed

+62
-30
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
547547
/** An extractor for def of a closure contained the block of the closure. */
548548
object closureDef {
549549
def unapply(tree: Tree): Option[DefDef] = tree match {
550+
case Block(Nil, expr) => unapply(expr)
550551
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, closure: Closure) =>
551552
Some(meth)
552553
case _ => None

compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ class TreeTypeMap(
9595
val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss)
9696
val res = cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs))
9797
res.symbol.transformAnnotations {
98-
case ann: BodyAnnotation => ann.derivedAnnotation(res.rhs)
98+
case ann: BodyAnnotation =>
99+
if (res.symbol.isTransparentMethod) ann.derivedAnnotation(transform(ann.tree))
100+
else ann.derivedAnnotation(res.rhs)
99101
case ann => ann
100102
}
101103
res
@@ -126,7 +128,7 @@ class TreeTypeMap(
126128
override def transformStats(trees: List[tpd.Tree])(implicit ctx: Context) =
127129
transformDefs(trees)._2
128130

129-
private def transformDefs[TT <: tpd.Tree](trees: List[TT])(implicit ctx: Context): (TreeTypeMap, List[TT]) = {
131+
def transformDefs[TT <: tpd.Tree](trees: List[TT])(implicit ctx: Context): (TreeTypeMap, List[TT]) = {
130132
val tmap = withMappedSyms(tpd.localSyms(trees))
131133
(tmap, tmap.transformSub(trees))
132134
}

compiler/src/dotty/tools/dotc/ast/tpd.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import scala.io.Codec
2020
/** Some creators for typed trees */
2121
object tpd extends Trees.Instance[Type] with TypedTreeInfo {
2222

23+
case class UntypedSplice(splice: untpd.Tree) extends Tree
24+
2325
private def ta(implicit ctx: Context) = ctx.typeAssigner
2426

2527
def Ident(tp: NamedType)(implicit ctx: Context): Ident =
@@ -471,8 +473,6 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
471473
} else foldOver(sym, tree)
472474
}
473475

474-
case class UntypedSplice(splice: untpd.Tree) extends Tree
475-
476476
override val cpy: TypedTreeCopier = // Type ascription needed to pick up any new members in TreeCopier (currently there are none)
477477
new TypedTreeCopier
478478

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,8 @@ class TreePickler(pickler: TastyPickler) {
637637
// a different toplevel class, it is impossible to pickle a reference to it.
638638
// Such annotations will be reconstituted when unpickling the child class.
639639
// See tests/pickling/i3149.scala
640-
case _ => ann.symbol == defn.BodyAnnot
641-
// inline bodies are reconstituted automatically when unpickling
640+
case _ => ann.symbol == defn.BodyAnnot && owner.isInlinedMethod
641+
// bodies of inlined (but not transparent) methods are reconstituted automatically when unpickling
642642
}
643643

644644
def pickleAnnotation(owner: Symbol, ann: Annotation)(implicit ctx: Context) =

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -634,9 +634,12 @@ class TreeUnpickler(reader: TastyReader,
634634
val end = readEnd()
635635
val tp = readType()
636636
val lazyAnnotTree = readLater(end, rdr => ctx => rdr.readTerm()(ctx))
637-
Annotation.deferredSymAndTree(
638-
implicit ctx => tp.typeSymbol,
639-
implicit ctx => lazyAnnotTree.complete)
637+
if (tp.isRef(defn.BodyAnnot))
638+
LazyBodyAnnotation(implicit ctx => lazyAnnotTree.complete)
639+
else
640+
Annotation.deferredSymAndTree(
641+
implicit ctx => tp.typeSymbol,
642+
implicit ctx => lazyAnnotTree.complete)
640643
}
641644

642645
/** Create symbols for the definitions in the statement sequence between

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

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,19 +1103,24 @@ trait Implicits { self: Typer =>
11031103
val eligible =
11041104
if (contextual) ctx.implicits.eligible(wildProto)
11051105
else implicitScope(wildProto).eligible
1106-
searchImplicits(eligible, contextual).recoverWith {
1107-
failure => failure.reason match {
1108-
case _: AmbiguousImplicits => failure
1109-
case reason =>
1110-
if (contextual)
1111-
bestImplicit(contextual = false).recoverWith {
1112-
failure2 => reason match {
1113-
case (_: DivergingImplicit) | (_: ShadowedImplicit) => failure
1114-
case _ => failure2
1106+
searchImplicits(eligible, contextual) match {
1107+
case result: SearchSuccess =>
1108+
if (contextual && ctx.mode.is(Mode.TransparentBody))
1109+
Inliner.markContextualImplicit(result.tree)
1110+
result
1111+
case failure: SearchFailure =>
1112+
failure.reason match {
1113+
case _: AmbiguousImplicits => failure
1114+
case reason =>
1115+
if (contextual)
1116+
bestImplicit(contextual = false).recoverWith {
1117+
failure2 => reason match {
1118+
case (_: DivergingImplicit) | (_: ShadowedImplicit) => failure
1119+
case _ => failure2
1120+
}
11151121
}
1116-
}
1117-
else failure
1118-
}
1122+
else failure
1123+
}
11191124
}
11201125
}
11211126

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,20 @@ import collection.mutable
2727
import transform.TypeUtils._
2828
import reporting.trace
2929
import util.Positions.Position
30+
import util.Property
3031

3132
object Inliner {
3233
import tpd._
3334

35+
/** Marks an implicit reference found in the context (as opposed to the implicit scope)
36+
* from an inlineable body. Such references will be carried along with the body to
37+
* the expansion site.
38+
*/
39+
private val ContextualImplicit = new Property.StickyKey[Unit]
40+
41+
def markContextualImplicit(tree: Tree)(implicit ctx: Context): Unit =
42+
methPart(tree).putAttachment(ContextualImplicit, ())
43+
3444
class InlineAccessors extends AccessProxies {
3545

3646
/** A tree map which inserts accessors for all non-public term members accessed
@@ -104,7 +114,7 @@ object Inliner {
104114
* to have the inlined method as owner.
105115
*/
106116
def registerInlineInfo(
107-
sym: SymDenotation, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
117+
sym: SymDenotation, originalBody: untpd.Tree, treeExpr: Context => Tree)(implicit ctx: Context): Unit = {
108118
sym.unforcedAnnotation(defn.BodyAnnot) match {
109119
case Some(ann: ConcreteBodyAnnotation) =>
110120
case Some(ann: LazyBodyAnnotation) if ann.isEvaluated =>
@@ -173,10 +183,10 @@ object Inliner {
173183

174184
/** Produces an inlined version of `call` via its `inlined` method.
175185
*
176-
* @param call The original call to a `@inline` method
177-
* @param rhs The body of the inline method that replaces the call.
186+
* @param call the original call to a `@inline` method
187+
* @param rhsToInline the body of the inline method that replaces the call.
178188
*/
179-
class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
189+
class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
180190
import tpd._
181191
import Inliner._
182192

@@ -200,7 +210,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
200210
*/
201211
private val paramProxy = new mutable.HashMap[Type, Type]
202212

203-
/** A map from the classes of (direct and outer) this references in `rhs`
213+
/** A map from the classes of (direct and outer) this references in `rhsToInline`
204214
* to references of their proxies.
205215
* Note that we can't index by the ThisType itself since there are several
206216
* possible forms to express what is logicaly the same ThisType. E.g.
@@ -315,7 +325,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
315325
if (!isIdempotentExpr(prefix)) registerType(meth.owner.thisType)
316326

317327
// Register types of all leaves of inlined body so that the `paramProxy` and `thisProxy` maps are defined.
318-
rhs.foreachSubTree(registerLeaf)
328+
rhsToInline.foreachSubTree(registerLeaf)
319329

320330
// The class that the this-proxy `selfSym` represents
321331
def classOf(selfSym: Symbol) = selfSym.info.widen.classSymbol
@@ -387,7 +397,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) {
387397
// the owner from the inlined method to the current owner.
388398
val inliner = new TreeTypeMap(typeMap, treeMap, meth :: Nil, ctx.owner :: Nil)(inlineCtx)
389399

390-
val expansion = inliner(rhs.withPos(call.pos))
400+
val expansion = inliner(rhsToInline.withPos(call.pos))
391401
trace(i"inlining $call\n, BINDINGS =\n${bindingsBuf.toList}%\n%\nEXPANSION =\n$expansion", inlining, show = true) {
392402

393403
// The final expansion runs a typing pass over the inlined tree. See InlineTyper for details.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ class Namer { typer: Typer =>
825825
case original: untpd.DefDef if denot.isInlineableMethod =>
826826
Inliner.registerInlineInfo(
827827
denot,
828+
original.rhs,
828829
implicit ctx => typedAheadExpr(original).asInstanceOf[tpd.DefDef].rhs
829830
)(localContext(denot.symbol))
830831
case _ =>

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,7 +1420,7 @@ class Typer extends Namer
14201420
val rhs1 = normalizeErasedRhs(typedExpr(ddef.rhs, tpt1.tpe)(rhsCtx), sym)
14211421

14221422
// Overwrite inline body to make sure it is not evaluated twice
1423-
if (sym.isInlineableMethod) Inliner.registerInlineInfo(sym, _ => rhs1)
1423+
if (sym.isInlineableMethod) Inliner.registerInlineInfo(sym, ddef.rhs, _ => rhs1)
14241424

14251425
if (sym.isConstructor && !sym.isPrimaryConstructor)
14261426
for (param <- tparams1 ::: vparamss1.flatten)
@@ -1885,7 +1885,17 @@ class Typer extends Namer
18851885
case none =>
18861886
typed(mdef) match {
18871887
case mdef1: DefDef if Inliner.hasBodyToInline(mdef1.symbol) =>
1888-
buf += inlineExpansion(mdef1)
1888+
if (mdef1.symbol.isInlinedMethod) {
1889+
buf += inlineExpansion(mdef1)
1890+
// replace body with expansion, because it will be used as inlined body
1891+
// from separately compiled files - the original BodyAnnotation is not kept.
1892+
}
1893+
else {
1894+
assert(mdef.symbol.isTransparentMethod)
1895+
Inliner.bodyToInline(mdef1.symbol) // just make sure accessors are computed,
1896+
buf += mdef1 // but keep original definition, since inline-expanded code
1897+
// is pickled in this case.
1898+
}
18891899
case mdef1 =>
18901900
import untpd.modsDeco
18911901
mdef match {

0 commit comments

Comments
 (0)