Skip to content

Commit b2633f9

Browse files
committed
Go back to inlining during typing
Reverts the following commits: Join containsQuotesOrSplices and containsInlineCalls (reverted from commit 8cf1385) Make InlineCalls an object (reverted from commit ad26554) Remove Inlined and InlineProxy from TASTy (reverted from commit 976e095) Move inlining inside Reify quotes Split some neg tests as now only the first error is emitted. (reverted from commit 21e65f1) Erase rhs of erased non inlined val/def in PostTyper (reverted from commit c12e875) Add isInlineCall to TreeInfo (reverted from commit 954c25b) Update doc (reverted from commit 0832e02) Only run InlineCalls if the tree contains an inline call (reverted from commit f28e2e1) Check if unpickled tree has inline nodes (reverted from commit 927ae4e) Add a bit of documentation (reverted from commit da0c249) Fix constant folding during inlining (reverted from commit 32c8798) Move inline β-reduction after Pickler (reverted from commit c68dc1f) Normalize call at Inlined node creation (reverted from commit 746fdd7) Move inline β-reduction after post typer (reverted from commit 432eb0a) Move inline β-reduction out of typer (reverted from commit 6acaf31)
1 parent 4385494 commit b2633f9

File tree

26 files changed

+143
-246
lines changed

26 files changed

+143
-246
lines changed

compiler/src/dotty/tools/dotc/CompilationUnit.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ package dotc
33

44
import util.SourceFile
55
import ast.{tpd, untpd}
6-
import dotty.tools.dotc.ast.Trees
76
import tpd.{Tree, TreeTraverser}
87
import typer.PrepareInlineable.InlineAccessors
98
import dotty.tools.dotc.core.Contexts.Context
109
import dotty.tools.dotc.core.SymDenotations.ClassDenotation
1110
import dotty.tools.dotc.core.Symbols._
1211
import dotty.tools.dotc.transform.SymUtils._
13-
import dotty.tools.dotc.typer.Inliner
1412

1513
class CompilationUnit(val source: SourceFile) {
1614

@@ -25,8 +23,8 @@ class CompilationUnit(val source: SourceFile) {
2523
/** Pickled TASTY binaries, indexed by class. */
2624
var pickled: Map[ClassSymbol, Array[Byte]] = Map()
2725

28-
/** Will be set to `true` if contains `Quote`, `Splice` or calls to inline methods.
29-
* The information is used in phase `Staging` in order to avoid traversing a quote-less tree.
26+
/** Will be set to `true` if contains `Quote`.
27+
* The information is used in phase `Staging` in order to avoid traversing trees that need no transformations.
3028
*/
3129
var needsStaging: Boolean = false
3230

@@ -57,8 +55,7 @@ object CompilationUnit {
5755
private class Force extends TreeTraverser {
5856
var needsStaging = false
5957
def traverse(tree: Tree)(implicit ctx: Context): Unit = {
60-
// Note that top-level splices are still inside the inline methods
61-
if (tree.symbol.isQuote || tpd.isInlineCall(tree))
58+
if (tree.symbol.isQuote)
6259
needsStaging = true
6360
traverseChildren(tree)
6461
}

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class Compiler {
4444
/** Phases dealing with TASTY tree pickling and unpickling */
4545
protected def picklerPhases: List[List[Phase]] =
4646
List(new Pickler) :: // Generate TASTY info
47-
List(new Staging) :: // Inline calls, expand macros and turn quoted trees into explicit run-time data structures
47+
List(new Staging) :: // Turn quoted trees into explicit run-time data structures
4848
Nil
4949

5050
/** Phases dealing with the transformation from pickled trees to backend trees */

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package ast
55
import core._
66
import Flags._, Trees._, Types._, Contexts._
77
import Names._, StdNames._, NameOps._, Symbols._
8-
import typer.{ConstFold, Inliner}
8+
import typer.ConstFold
99
import reporting.trace
1010

1111
import scala.annotation.tailrec
@@ -770,14 +770,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
770770
false
771771
}
772772

773-
/** Is this call a call to a method that is marked as Inline */
774-
def isInlineCall(arg: Tree)(implicit ctx: Context): Boolean = arg match {
775-
case _: RefTree | _: GenericApply[_] =>
776-
!arg.tpe.widenDealias.isInstanceOf[MethodicType] && Inliner.isInlineable(arg)
777-
case _ =>
778-
false
779-
}
780-
781773
/** Structural tree comparison (since == on trees is reference equality).
782774
* For the moment, only Ident, Select, Literal, Apply and TypeApply are supported
783775
*/

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,8 +585,9 @@ object Trees {
585585

586586
/** A tree representing inlined code.
587587
*
588-
* @param call Info about the original call that was inlined.
589-
* Only a reference to the toplevel class from which the call was inlined.
588+
* @param call Info about the original call that was inlined
589+
* Until PostTyper, this is the full call, afterwards only
590+
* a reference to the toplevel class from which the call was inlined.
590591
* @param bindings Bindings for proxies to be used in the inlined code
591592
* @param expansion The inlined tree, minus bindings.
592593
*

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

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ Standard-Section: "ASTs" TopLevelStat*
8686
TYPED Length expr_Term ascriptionType_Tern
8787
ASSIGN Length lhs_Term rhs_Term
8888
BLOCK Length expr_Term Stat*
89+
INLINED Length expr_Term call_Term? ValOrDefDef*
8990
LAMBDA Length meth_Term target_Type?
9091
IF Length cond_Term then_Term else_Term
9192
MATCH Length sel_Term CaseDef*
@@ -184,6 +185,7 @@ Standard-Section: "ASTs" TopLevelStat*
184185
OVERRIDE
185186
INLINE
186187
MACRO // inline method containing toplevel splices
188+
INLINEPROXY // symbol of binding representing an inline parameter
187189
STATIC // mapped to static Java member
188190
OBJECT // an object or its class
189191
TRAIT // a trait
@@ -233,7 +235,7 @@ Standard Section: "Comments" Comment*
233235
object TastyFormat {
234236

235237
final val header: Array[Int] = Array(0x5C, 0xA1, 0xAB, 0x1F)
236-
val MajorVersion: Int = 13
238+
val MajorVersion: Int = 11
237239
val MinorVersion: Int = 0
238240

239241
/** Tags used to serialize names */
@@ -286,25 +288,26 @@ object TastyFormat {
286288
final val IMPLICIT = 13
287289
final val LAZY = 14
288290
final val OVERRIDE = 15
289-
final val INLINE = 16
290-
final val STATIC = 17
291-
final val OBJECT = 18
292-
final val TRAIT = 19
293-
final val ENUM = 20
294-
final val LOCAL = 21
295-
final val SYNTHETIC = 22
296-
final val ARTIFACT = 23
297-
final val MUTABLE = 24
298-
final val FIELDaccessor = 25
299-
final val CASEaccessor = 26
300-
final val COVARIANT = 27
301-
final val CONTRAVARIANT = 28
302-
final val SCALA2X = 29
303-
final val DEFAULTparameterized = 30
304-
final val STABLE = 31
305-
final val MACRO = 32
306-
final val ERASED = 33
307-
final val PARAMsetter = 34
291+
final val INLINEPROXY = 16
292+
final val INLINE = 17
293+
final val STATIC = 18
294+
final val OBJECT = 19
295+
final val TRAIT = 20
296+
final val ENUM = 21
297+
final val LOCAL = 22
298+
final val SYNTHETIC = 23
299+
final val ARTIFACT = 24
300+
final val MUTABLE = 25
301+
final val FIELDaccessor = 26
302+
final val CASEaccessor = 27
303+
final val COVARIANT = 28
304+
final val CONTRAVARIANT = 29
305+
final val SCALA2X = 30
306+
final val DEFAULTparameterized = 31
307+
final val STABLE = 32
308+
final val MACRO = 33
309+
final val ERASED = 34
310+
final val PARAMsetter = 35
308311

309312
// Cat. 2: tag Nat
310313

@@ -378,35 +381,36 @@ object TastyFormat {
378381
final val RETURN = 144
379382
final val WHILE = 145
380383
final val TRY = 146
381-
final val SELECTouter = 147
382-
final val REPEATED = 148
383-
final val BIND = 149
384-
final val ALTERNATIVE = 150
385-
final val UNAPPLY = 151
386-
final val ANNOTATEDtype = 152
387-
final val ANNOTATEDtpt = 153
388-
final val CASEDEF = 154
389-
final val TEMPLATE = 155
390-
final val SUPER = 156
391-
final val SUPERtype = 157
392-
final val REFINEDtype = 158
393-
final val REFINEDtpt = 159
394-
final val APPLIEDtype = 160
395-
final val APPLIEDtpt = 161
396-
final val TYPEBOUNDS = 162
397-
final val TYPEBOUNDStpt = 163
398-
final val ANDtype = 164
399-
final val ANDtpt = 165
400-
final val ORtype = 166
401-
final val ORtpt = 167
402-
final val POLYtype = 168
403-
final val TYPELAMBDAtype = 169
404-
final val LAMBDAtpt = 170
405-
final val PARAMtype = 171
406-
final val ANNOTATION = 172
407-
final val TERMREFin = 173
408-
final val TYPEREFin = 174
409-
final val OBJECTDEF = 175
384+
final val INLINED = 147
385+
final val SELECTouter = 148
386+
final val REPEATED = 149
387+
final val BIND = 150
388+
final val ALTERNATIVE = 151
389+
final val UNAPPLY = 152
390+
final val ANNOTATEDtype = 153
391+
final val ANNOTATEDtpt = 154
392+
final val CASEDEF = 155
393+
final val TEMPLATE = 156
394+
final val SUPER = 157
395+
final val SUPERtype = 158
396+
final val REFINEDtype = 159
397+
final val REFINEDtpt = 160
398+
final val APPLIEDtype = 161
399+
final val APPLIEDtpt = 162
400+
final val TYPEBOUNDS = 163
401+
final val TYPEBOUNDStpt = 164
402+
final val ANDtype = 165
403+
final val ANDtpt = 166
404+
final val ORtype = 167
405+
final val ORtpt = 168
406+
final val POLYtype = 169
407+
final val TYPELAMBDAtype = 170
408+
final val LAMBDAtpt = 171
409+
final val PARAMtype = 172
410+
final val ANNOTATION = 173
411+
final val TERMREFin = 174
412+
final val TYPEREFin = 175
413+
final val OBJECTDEF = 176
410414

411415
// In binary: 101101EI
412416
// I = implicit method type
@@ -456,6 +460,7 @@ object TastyFormat {
456460
| LAZY
457461
| OVERRIDE
458462
| INLINE
463+
| INLINEPROXY
459464
| MACRO
460465
| STATIC
461466
| OBJECT
@@ -512,6 +517,7 @@ object TastyFormat {
512517
case LAZY => "LAZY"
513518
case OVERRIDE => "OVERRIDE"
514519
case INLINE => "INLINE"
520+
case INLINEPROXY => "INLINEPROXY"
515521
case MACRO => "MACRO"
516522
case STATIC => "STATIC"
517523
case OBJECT => "OBJECT"
@@ -579,6 +585,7 @@ object TastyFormat {
579585
case MATCH => "MATCH"
580586
case RETURN => "RETURN"
581587
case WHILE => "WHILE"
588+
case INLINED => "INLINED"
582589
case SELECTouter => "SELECTouter"
583590
case TRY => "TRY"
584591
case REPEATED => "REPEATED"

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,17 @@ class TreePickler(pickler: TastyPickler) {
442442
case SeqLiteral(elems, elemtpt) =>
443443
writeByte(REPEATED)
444444
withLength { pickleTree(elemtpt); elems.foreach(pickleTree) }
445+
case Inlined(call, bindings, expansion) =>
446+
writeByte(INLINED)
447+
bindings.foreach(preRegister)
448+
withLength {
449+
pickleTree(expansion)
450+
if (!call.isEmpty) pickleTree(call)
451+
bindings.foreach { b =>
452+
assert(b.isInstanceOf[DefDef] || b.isInstanceOf[ValDef])
453+
pickleTree(b)
454+
}
455+
}
445456
case Bind(name, body) =>
446457
registerDef(tree.symbol)
447458
writeByte(BIND)
@@ -608,6 +619,7 @@ class TreePickler(pickler: TastyPickler) {
608619
if (flags is Case) writeByte(CASE)
609620
if (flags is Override) writeByte(OVERRIDE)
610621
if (flags is Inline) writeByte(INLINE)
622+
if (flags is InlineProxy) writeByte(INLINEPROXY)
611623
if (flags is Macro) writeByte(MACRO)
612624
if (flags is JavaStatic) writeByte(STATIC)
613625
if (flags is Module) writeByte(OBJECT)

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,7 @@ class TreeUnpickler(reader: TastyReader,
604604
case LAZY => addFlag(Lazy)
605605
case OVERRIDE => addFlag(Override)
606606
case INLINE => addFlag(Inline)
607+
case INLINEPROXY => addFlag(InlineProxy)
607608
case MACRO => addFlag(Macro)
608609
case STATIC => addFlag(JavaStatic)
609610
case OBJECT => addFlag(Module)
@@ -1072,6 +1073,17 @@ class TreeUnpickler(reader: TastyReader,
10721073
val stats = readStats(ctx.owner, end)
10731074
val expr = exprReader.readTerm()
10741075
Block(stats, expr)
1076+
case INLINED =>
1077+
val exprReader = fork
1078+
skipTree()
1079+
def maybeCall = nextUnsharedTag match {
1080+
case VALDEF | DEFDEF => EmptyTree
1081+
case _ => readTerm()
1082+
}
1083+
val call = ifBefore(end)(maybeCall, EmptyTree)
1084+
val bindings = readStats(ctx.owner, end).asInstanceOf[List[ValOrDefDef]]
1085+
val expansion = exprReader.readTerm() // need bindings in scope, so needs to be read before
1086+
Inlined(call, bindings, expansion)
10751087
case IF =>
10761088
If(readTerm(), readTerm(), readTerm())
10771089
case LAMBDA =>

compiler/src/dotty/tools/dotc/decompiler/TASTYDecompiler.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class TASTYDecompiler extends TASTYCompiler {
1515
Nil
1616

1717
override protected def picklerPhases: List[List[Phase]] = Nil
18-
1918
override protected def transformPhases: List[List[Phase]] = Nil
2019

2120
override protected def backendPhases: List[List[Phase]] =

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ object PostTyper {
4040
*
4141
* (10) Adds Child annotations to all sealed classes
4242
*
43-
* (11) Replace RHS of `erased` (but not `inline`) members by `(???: rhs.type)`
43+
* (11) Minimizes `call` fields of `Inlined` nodes to just point to the toplevel
44+
* class from which code was inlined.
4445
*
4546
* The reason for making this a macro transform is that some functions (in particular
4647
* super and protected accessors and instantiation checks) are naturally top-down and
@@ -177,22 +178,23 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
177178
}
178179
}
179180

180-
private def handleInlineCall(sym: Symbol)(implicit ctx: Context): Unit = {
181-
if (sym.is(Inline))
182-
ctx.compilationUnit.needsStaging = true
181+
private object dropInlines extends TreeMap {
182+
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
183+
case Inlined(call, _, _) =>
184+
cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe)))
185+
case _ => super.transform(tree)
186+
}
183187
}
184188

185189
override def transform(tree: Tree)(implicit ctx: Context): Tree =
186190
try tree match {
187191
case tree: Ident if !tree.isType =>
188-
handleInlineCall(tree.symbol)
189192
handleMeta(tree.symbol)
190193
tree.tpe match {
191194
case tpe: ThisType => This(tpe.cls).withPos(tree.pos)
192195
case _ => tree
193196
}
194197
case tree @ Select(qual, name) =>
195-
handleInlineCall(tree.symbol)
196198
handleMeta(tree.symbol)
197199
if (name.isTypeName) {
198200
Checking.checkRealizable(qual.tpe, qual.pos.focus)
@@ -201,15 +203,14 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
201203
else
202204
transformSelect(tree, Nil)
203205
case tree: Apply =>
204-
handleInlineCall(tree.symbol)
205206
val methType = tree.fun.tpe.widen
206207
val app =
207208
if (methType.isErasedMethod)
208209
tpd.cpy.Apply(tree)(
209210
tree.fun,
210211
tree.args.map(arg =>
211212
if (methType.isImplicitMethod && arg.pos.isSynthetic) ref(defn.Predef_undefined)
212-
else arg))
213+
else dropInlines.transform(arg)))
213214
else
214215
tree
215216
methPart(app) match {
@@ -222,7 +223,6 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
222223
super.transform(app)
223224
}
224225
case tree: TypeApply =>
225-
handleInlineCall(tree.symbol)
226226
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
227227
if (fn.symbol != defn.ChildAnnot.primaryConstructor) {
228228
// Make an exception for ChildAnnot, which should really have AnyKind bounds
@@ -236,6 +236,19 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
236236
case _ =>
237237
super.transform(tree1)
238238
}
239+
case Inlined(call, bindings, expansion) if !call.isEmpty =>
240+
// Leave only a call trace consisting of
241+
// - a reference to the top-level class from which the call was inlined,
242+
// - the call's position
243+
// in the call field of an Inlined node.
244+
// The trace has enough info to completely reconstruct positions.
245+
// The minimization is done for two reasons:
246+
// 1. To save space (calls might contain large inline arguments, which would otherwise
247+
// be duplicated
248+
// 2. To enable correct pickling (calls can share symbols with the inlined code, which
249+
// would trigger an assertion when pickling).
250+
val callTrace = Ident(call.symbol.topLevelClass.typeRef).withPos(call.pos)
251+
cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(inlineContext(call)))
239252
case tree: Template =>
240253
withNoCheckNews(tree.parents.flatMap(newPart)) {
241254
val templ1 = paramFwd.forwardParamAccessors(tree)
@@ -322,10 +335,9 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
322335
}
323336

324337
/** Transforms the rhs tree into a its default tree if it is in an `erased` val/def.
325-
* Performed to shrink the tree that is known to be erased later.
326-
*/
338+
* Performed to shrink the tree that is known to be erased later.
339+
*/
327340
private def normalizeErasedRhs(rhs: Tree, sym: Symbol)(implicit ctx: Context) =
328-
if (!sym.isEffectivelyErased || sym.isInlineMethod || !rhs.tpe.exists) rhs
329-
else Typed(ref(defn.Predef_undefined), TypeTree(rhs.tpe))
341+
if (sym.isEffectivelyErased) dropInlines.transform(rhs) else rhs
330342
}
331343
}

0 commit comments

Comments
 (0)