Skip to content

Commit d8ada9b

Browse files
committed
Bring back typed inliner
1 parent 5ae13c9 commit d8ada9b

File tree

8 files changed

+85
-26
lines changed

8 files changed

+85
-26
lines changed

compiler/src/dotty/tools/dotc/core/Contexts.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ object Contexts {
309309

310310
/** Is this a context for typechecking an inlined body? */
311311
def isInlineContext: Boolean =
312-
typer.isInstanceOf[Inliner#InlineTyper]
312+
typer.isInstanceOf[Inliner#InlineTyping]
313313

314314
/** The next outer context whose tree is a template or package definition
315315
* Note: Currently unused

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,9 @@ class TreePickler(pickler: TastyPickler) {
652652
// a different toplevel class, it is impossible to pickle a reference to it.
653653
// Such annotations will be reconstituted when unpickling the child class.
654654
// See tests/pickling/i3149.scala
655-
case _ => false
655+
case _ =>
656+
if (Inliner.typedInline) ann.symbol == defn.BodyAnnot // inline bodies are reconstituted automatically when unpickling
657+
else false
656658
}
657659

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

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import core.quoted.PickledQuotes
2424
import scala.quoted
2525
import scala.quoted.Types.TreeType
2626
import scala.quoted.Exprs.TastyTreeExpr
27+
import typer.Inliner.typedInline
2728

2829
import scala.annotation.internal.sharable
2930

@@ -556,6 +557,12 @@ class TreeUnpickler(reader: TastyReader,
556557
sym.completer.withDecls(newScope)
557558
forkAt(templateStart).indexTemplateParams()(localContext(sym))
558559
}
560+
else if (typedInline && sym.isInlineMethod)
561+
sym.addAnnotation(LazyBodyAnnotation { ctx0 =>
562+
implicit val ctx: Context = localContext(sym)(ctx0).addMode(Mode.ReadPositions)
563+
// avoids space leaks by not capturing the current context
564+
forkAt(rhsStart).readTerm()
565+
})
559566
goto(start)
560567
sym
561568
}
@@ -637,8 +644,10 @@ class TreeUnpickler(reader: TastyReader,
637644
val lazyAnnotTree = readLaterWithOwner(end, rdr => ctx => rdr.readTerm()(ctx))
638645

639646
owner =>
640-
if (tp.isRef(defn.BodyAnnot))
647+
if (tp.isRef(defn.BodyAnnot)) {
648+
assert(!typedInline)
641649
LazyBodyAnnotation(implicit ctx => lazyAnnotTree(owner).complete)
650+
}
642651
else
643652
Annotation.deferredSymAndTree(
644653
implicit ctx => tp.typeSymbol,
@@ -741,6 +750,11 @@ class TreeUnpickler(reader: TastyReader,
741750
def readRhs(implicit ctx: Context) =
742751
if (nothingButMods(end))
743752
EmptyTree
753+
else if (sym.isInlineMethod && typedInline)
754+
// The body of an inline method is stored in an annotation, so no need to unpickle it again
755+
new Trees.Lazy[Tree] {
756+
def complete(implicit ctx: Context) = typer.Inliner.bodyToInline(sym)
757+
}
744758
else
745759
readLater(end, rdr => ctx => rdr.readTerm()(ctx.retractMode(Mode.InSuperCall)))
746760

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

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ import ast.TreeInfo
3434
object Inliner {
3535
import tpd._
3636

37+
val typedInline = true
38+
3739
/** A key to be used in a context property that provides a map from enclosing implicit
3840
* value bindings to their right hand sides.
3941
*/
@@ -382,7 +384,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
382384
// Compute bindings for all this-proxies, appending them to bindingsBuf
383385
computeThisBindings()
384386

385-
val inlineTyper = new InlineTyper
387+
val inlineTyper =
388+
if (typedInline) new InlineReTyper else new TransparentTyper
389+
386390
val inlineCtx = inlineContext(call).fresh.setTyper(inlineTyper).setNewScope
387391

388392
// A tree type map to prepare the inlined body for typechecked.
@@ -857,7 +861,7 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
857861
* 4. Make sure inlined code is type-correct.
858862
* 5. Make sure that the tree's typing is idempotent (so that future -Ycheck passes succeed)
859863
*/
860-
class InlineTyper extends Typer {
864+
trait InlineTyping extends Typer {
861865
import reducer._
862866

863867
override def ensureAccessible(tpe: Type, superAccess: Boolean, pos: Position)(implicit ctx: Context): Type = {
@@ -873,12 +877,6 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
873877
super.ensureAccessible(tpe, superAccess, pos)
874878
}
875879

876-
override def typedTypedSplice(tree: untpd.TypedSplice)(implicit ctx: Context): Tree =
877-
reduceProjection(tryInline(tree.splice) `orElse` super.typedTypedSplice(tree))
878-
879-
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context) =
880-
constToLiteral(reduceProjection(super.typedSelect(tree, pt)))
881-
882880
override def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context) =
883881
typed(tree.cond, defn.BooleanType) match {
884882
case cond1 @ ConstantValue(b: Boolean) =>
@@ -895,6 +893,19 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
895893
super.typedIf(if1, pt)
896894
}
897895

896+
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context) =
897+
constToLiteral(betaReduce(super.typedApply(tree, pt)))
898+
}
899+
900+
private class TransparentTyper extends Typer with InlineTyping {
901+
import reducer._
902+
903+
override def typedTypedSplice(tree: untpd.TypedSplice)(implicit ctx: Context): Tree =
904+
reduceProjection(tryInline(tree.splice) `orElse` super.typedTypedSplice(tree))
905+
906+
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context) =
907+
constToLiteral(reduceProjection(super.typedSelect(tree, pt)))
908+
898909
override def typedMatchFinish(tree: untpd.Match, sel: Tree, selType: Type, pt: Type)(implicit ctx: Context) = tree match {
899910
case _: untpd.InlineMatch if !ctx.owner.isInlineMethod => // don't reduce match of nested inline method yet
900911
reduceInlineMatch(sel, sel.tpe, tree.cases, this) match {
@@ -916,10 +927,24 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) {
916927
super.typedMatchFinish(tree, sel, selType, pt)
917928
}
918929

919-
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context) =
920-
constToLiteral(betaReduce(super.typedApply(tree, pt)))
930+
override def newLikeThis: Typer = new TransparentTyper
931+
}
932+
933+
private class InlineReTyper extends ReTyper with InlineTyping {
934+
import reducer._
935+
936+
override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context) =
937+
tryInline(tree.asInstanceOf[tpd.Tree]) `orElse` super.typedIdent(tree, pt)
938+
939+
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
940+
assert(tree.hasType, tree)
941+
val qual1 = typed(tree.qualifier, selectionProto(tree.name, pt, this))
942+
val res = untpd.cpy.Select(tree)(qual1, tree.name).withType(tree.typeOpt)
943+
ensureAccessible(res.tpe, tree.qualifier.isInstanceOf[untpd.Super], tree.pos)
944+
res
945+
}
921946

922-
override def newLikeThis: Typer = new InlineTyper
947+
override def newLikeThis: Typer = new InlineReTyper
923948
}
924949

925950
/** Drop any side-effect-free bindings that are unused in expansion or other reachable bindings.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,10 @@ object PrepareInlineable {
243243
val typedBody =
244244
if (ctx.reporter.hasErrors) rawBody
245245
else ctx.compilationUnit.inlineAccessors.makeInlineable(rawBody)
246-
if (inlined.isInlineMethod)
247-
checkInlineMethod(inlined, typedBody)
248-
val inlineableBody = addReferences(inlined, originalBody, typedBody)
246+
checkInlineMethod(inlined, typedBody)
247+
val inlineableBody =
248+
if (Inliner.typedInline) typedBody
249+
else addReferences(inlined, originalBody, typedBody)
249250
inlining.println(i"Body to inline for $inlined: $inlineableBody")
250251
inlineableBody
251252
})

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ object ProtoTypes {
8181
* achieved by replacing expected type parameters with wildcards.
8282
*/
8383
def constrainResult(meth: Symbol, mt: Type, pt: Type)(implicit ctx: Context): Boolean =
84-
if (Inliner.isInlineable(meth)) {
84+
if (Inliner.isInlineable(meth) && !Inliner.typedInline) {
8585
constrainResult(mt, wildApprox(pt))
8686
true
8787
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ class ReTyper extends Typer with ReChecking {
117117
throw ex
118118
}
119119

120+
override def inlineExpansion(mdef: DefDef)(implicit ctx: Context): Tree = mdef
121+
120122
override def checkVariance(tree: Tree)(implicit ctx: Context) = ()
121123
override def inferView(from: Tree, to: Type)(implicit ctx: Context): Implicits.SearchResult =
122124
Implicits.NoMatchingImplicitsFailure

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

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ class Typer extends Namer
711711
}
712712

713713
def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree = track("typedIf") {
714-
if (tree.isInstanceOf[untpd.InlineIf]) checkInInlineContext("inline if", tree.pos)
714+
if (tree.isInstanceOf[untpd.InlineIf] && !Inliner.typedInline) checkInInlineContext("inline if", tree.pos)
715715
val cond1 = typed(tree.cond, defn.BooleanType)
716716
val thenp2 :: elsep2 :: Nil = harmonic(harmonize) {
717717
val thenp1 = typed(tree.thenp, pt.notApplied)
@@ -981,7 +981,7 @@ class Typer extends Namer
981981
val sel1 = id.withType(defn.ImplicitScrutineeTypeRef)
982982
typedMatchFinish(tree, sel1, sel1.tpe, pt)
983983
case _ =>
984-
if (tree.isInstanceOf[untpd.InlineMatch]) checkInInlineContext("inline match", tree.pos)
984+
if (tree.isInstanceOf[untpd.InlineMatch] && !Inliner.typedInline) checkInInlineContext("inline match", tree.pos)
985985
val sel1 = typedExpr(tree.selector)
986986
val selType = fullyDefinedType(sel1.tpe, "pattern selector", tree.pos).widen
987987
typedMatchFinish(tree, sel1, selType, pt)
@@ -1992,10 +1992,17 @@ class Typer extends Namer
19921992
case none =>
19931993
typed(mdef) match {
19941994
case mdef1: DefDef if Inliner.hasBodyToInline(mdef1.symbol) =>
1995-
assert(mdef1.symbol.isInlineMethod, mdef.symbol)
1996-
Inliner.bodyToInline(mdef1.symbol) // just make sure accessors are computed,
1997-
buf += mdef1 // but keep original definition, since inline-expanded code
1998-
// is pickled in this case.
1995+
if (Inliner.typedInline) {
1996+
buf += inlineExpansion(mdef1)
1997+
// replace body with expansion, because it will be used as inlined body
1998+
// from separately compiled files - the original BodyAnnotation is not kept.
1999+
}
2000+
else {
2001+
assert(mdef1.symbol.isInlineMethod, mdef.symbol)
2002+
Inliner.bodyToInline(mdef1.symbol) // just make sure accessors are computed,
2003+
buf += mdef1 // but keep original definition, since inline-expanded code
2004+
// is pickled in this case.
2005+
}
19992006
case mdef1 =>
20002007
import untpd.modsDeco
20012008
mdef match {
@@ -2027,6 +2034,13 @@ class Typer extends Namer
20272034
checkEnumCompanions(traverse(stats)(localCtx), enumContexts)
20282035
}
20292036

2037+
/** Given an inline method `mdef`, the method rewritten so that its body
2038+
* uses accessors to access non-public members.
2039+
* Overwritten in Retyper to return `mdef` unchanged.
2040+
*/
2041+
protected def inlineExpansion(mdef: DefDef)(implicit ctx: Context): Tree =
2042+
tpd.cpy.DefDef(mdef)(rhs = Inliner.bodyToInline(mdef.symbol))
2043+
20302044
def typedExpr(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree =
20312045
typed(tree, pt)(ctx retractMode Mode.PatternOrTypeBits)
20322046
def typedType(tree: untpd.Tree, pt: Type = WildcardType)(implicit ctx: Context): Tree = // todo: retract mode between Type and Pattern?
@@ -2438,8 +2452,9 @@ class Typer extends Namer
24382452
else if (Inliner.isInlineable(tree) &&
24392453
!ctx.settings.YnoInline.value &&
24402454
!ctx.isAfterTyper &&
2441-
!ctx.reporter.hasErrors) {
2442-
tree.tpe <:< wildApprox(pt)
2455+
!ctx.reporter.hasErrors &&
2456+
(!Inliner.typedInline || tree.tpe <:< pt)) {
2457+
if (!Inliner.typedInline) tree.tpe <:< wildApprox(pt)
24432458
readaptSimplified(Inliner.inlineCall(tree, pt))
24442459
}
24452460
else if (tree.tpe <:< pt) {

0 commit comments

Comments
 (0)