Skip to content

Implement inline #1492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 77 commits into from
Oct 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
56f01cd
Namer refactoing
odersky Aug 29, 2016
c87a9dd
First version of inline scheme
odersky Sep 1, 2016
d63a6ba
Make Context#moreProperties strongly typed
odersky Sep 1, 2016
8a3762a
Add Inlined tree node
odersky Sep 1, 2016
faba2b7
Track Inlined nodes in ctx.source
odersky Sep 1, 2016
617be51
Print inlining positions in error messages
odersky Sep 1, 2016
729815b
Implement inline if
odersky Sep 2, 2016
b8a1176
Avoid simple aliases in bindings
odersky Sep 2, 2016
6f9f29e
Recursive inlining tests
odersky Sep 2, 2016
a75fee2
Don't expand stat before recursion in namer
felixmulder Sep 2, 2016
fd7b60c
Fix stack overflow on recurs in namer
felixmulder Sep 2, 2016
a47a800
Simplify enclosingInlineds
odersky Sep 2, 2016
96d0573
Support separate compilation
odersky Sep 2, 2016
688cc89
Add check files
odersky Sep 4, 2016
333ec27
Set the positions of inlined trees wehn read form Tasty
odersky Sep 4, 2016
c1674dc
Neg test demonstrating inline positions under cross-compilation
odersky Sep 4, 2016
a81070c
Fix some problems in Inliner
odersky Sep 4, 2016
379bb24
Remove redundanr test
odersky Sep 4, 2016
be53234
Add comment missing from last PR
odersky Sep 4, 2016
9a48e7b
Don't inline after typer.
odersky Sep 4, 2016
7cce2d4
Harden Inliner.sourceFile
odersky Sep 4, 2016
0bd955e
Drop Inlined when homogenize
odersky Sep 5, 2016
1d93264
Handle outer this in Inliner
odersky Sep 5, 2016
ba6bc75
Add test for pattern matching against outer
odersky Sep 5, 2016
b84bcbf
Update check file
odersky Sep 5, 2016
29acee0
Move InlineTyper to Inliner class
odersky Sep 5, 2016
4dd8469
Avoid reference to local bindings in Inlined nodes
odersky Sep 5, 2016
3354557
Fix bugs related to type parameter remapping
odersky Sep 5, 2016
ebcc2bd
Fix problem with homogenize trees
odersky Sep 5, 2016
61e8ea4
Better diagnostics for TreeChecker
odersky Sep 5, 2016
04de4b5
Fix problems handling types in Inliner
odersky Sep 5, 2016
5396a6b
Better error message in TreePickler
odersky Sep 5, 2016
5a345e7
Inline key operations in dotty
odersky Sep 5, 2016
60b6c6a
Harden ReTyper so that it's fit for inlining
odersky Sep 5, 2016
d96cb84
Test case for closure inlining
odersky Sep 5, 2016
bd0660e
Juggling with close in RefinedPrinter
odersky Sep 6, 2016
19ab7ab
Make inline annotation @scala.inline.
odersky Sep 6, 2016
f8d7500
Fix problem affecting recursive inlines
odersky Sep 6, 2016
7f3b9ca
Handle Inlined blocks on ElimErasedValueType
odersky Sep 6, 2016
aa4d49d
Suppress inlining printing
odersky Sep 6, 2016
b538f84
Suppress inline in dottydoc test of standard library
odersky Sep 6, 2016
4253578
Better toString for TermRefWithSig
odersky Sep 7, 2016
bf3345a
Fix ExplicitSelf phase
odersky Sep 7, 2016
ae67c35
Add accessors for non-public members accessed from inline methods
odersky Sep 8, 2016
c9e45de
Support access for setting private vars from inlined code
odersky Sep 9, 2016
b1cda4f
Better names and documentation for Inliner.
odersky Sep 9, 2016
184296f
Inline argument closures to inline methods
odersky Sep 9, 2016
d1b933c
Fix bug in InlineableClosure
odersky Sep 9, 2016
6bf7768
Refactoring for registering InlineInfo
odersky Sep 10, 2016
8e66f53
More inline tests
odersky Sep 10, 2016
e93b7bf
Don't add inline accessors twice
odersky Sep 10, 2016
d575e58
Make inline a keyword
odersky Sep 10, 2016
b743a9b
Make inline methods and field effectively final
odersky Sep 11, 2016
975d297
Fix problem related to accessor generation under separate compilation
odersky Sep 11, 2016
b559aff
Add accessibility check for type of new
odersky Sep 11, 2016
845b689
Add inline for vals
odersky Sep 12, 2016
7537cfc
Document deviations from inline SIP
odersky Sep 12, 2016
4de907a
Always use implicit context at the current period
odersky Sep 12, 2016
65551d1
Don't drop inline closure bindings that are referred in the body
odersky Sep 13, 2016
84bc770
Drop annotations from dealias
odersky Sep 13, 2016
b5132e8
Change owner as necessary when typing a TypedSplice
odersky Sep 15, 2016
748d1d8
Generalize checkInlineConformant to functions
odersky Sep 13, 2016
c9fa504
Inline function parameters
odersky Sep 15, 2016
5a46d19
Handle inlining in inlining arguments
odersky Sep 15, 2016
95e488e
Use BodyAnnot to indicate rhs of inline method
odersky Sep 15, 2016
ce9efda
Add check file
odersky Sep 15, 2016
bef012d
Move logic from InlineInfo to BodyAnnot
odersky Sep 15, 2016
53b165e
Cleanups
odersky Sep 15, 2016
eb95a04
Remove incorrect special case for Inline purity checks
smarter Sep 23, 2016
f239bdb
Disable scaladoc generation for dotty
smarter Sep 30, 2016
d4f0069
Fix incremental compilation when inline method signature changes
smarter Sep 30, 2016
6821bac
Fix incremental compilation when inline method body changes
smarter Sep 30, 2016
e5119a0
Address @smarter's review comments
odersky Oct 2, 2016
e795437
Fix inline failure in the presence of unit conversion
odersky Oct 2, 2016
0093c5d
Add test case
odersky Oct 5, 2016
215b97c
DottyBytecodeTest: fix diffInstructions output
smarter Oct 5, 2016
e0a14e7
Add InlineBytecodeTests to check that inline really works
smarter Oct 5, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bridge/src/sbt-test/source-dependencies/inline/A.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object A {
def get: Int = 1
}
5 changes: 5 additions & 0 deletions bridge/src/sbt-test/source-dependencies/inline/C.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object C {
def main(args: Array[String]): Unit = {
val i: Int = B.getInline
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object B {
@inline def getInline: Int =
A.get
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object B {
@inline def getInline: Double =
A.get
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
object B {
@inline def getInline: Int =
sys.error("This is an expected failure when running C")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import sbt._
import Keys._

object DottyInjectedPlugin extends AutoPlugin {
override def requires = plugins.JvmPlugin
override def trigger = allRequirements

override val projectSettings = Seq(
scalaVersion := "0.1-SNAPSHOT",
scalaOrganization := "ch.epfl.lamp",
scalacOptions += "-language:Scala2",
scalaBinaryVersion := "2.11",
autoScalaLibrary := false,
libraryDependencies ++= Seq("org.scala-lang" % "scala-library" % "2.11.5"),
scalaCompilerBridgeSource := ("ch.epfl.lamp" % "dotty-bridge" % "0.1.1-SNAPSHOT" % "component").sources()
)
}
14 changes: 14 additions & 0 deletions bridge/src/sbt-test/source-dependencies/inline/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
$ copy-file changes/B1.scala B.scala
> compile

$ copy-file changes/B2.scala B.scala
# Compilation of C.scala should fail because B.getInline now has type Double instead of Int
-> compile

$ copy-file changes/B1.scala B.scala
> run

$ copy-file changes/B3.scala B.scala
# The body of B.getInline was changed so C.scala should be recompiled
# If it was recompiled, run should fail since B.getInline now throws an exception
-> run
5 changes: 3 additions & 2 deletions docs/SyntaxSummary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,14 +231,15 @@ grammar.
ClsParamClauses ::= {ClsParamClause} [[nl] `(' `implicit' ClsParams `)']
ClsParamClause ::= [nl] `(' [ClsParams] ')'
ClsParams ::= ClsParam {`' ClsParam}
ClsParam ::= {Annotation} [{Modifier} (`val' | `var')] Param ValDef(mods, id, tpe, expr) -- point of mods on val/var
ClsParam ::= {Annotation}
[{Modifier} (`val' | `var') | `inline'] Param ValDef(mods, id, tpe, expr) -- point of mods on val/var
Param ::= id `:' ParamType [`=' Expr]
| INT

DefParamClauses ::= {DefParamClause} [[nl] `(' `implicit' DefParams `)']
DefParamClause ::= [nl] `(' [DefParams] ')'
DefParams ::= DefParam {`,' DefParam}
DefParam ::= {Annotation} Param ValDef(mods, id, tpe, expr) -- point of mods at id.
DefParam ::= {Annotation} [`inline'] Param ValDef(mods, id, tpe, expr) -- point of mods at id.

Bindings ::= `(' Binding {`,' Binding `)' bindings
Binding ::= (id | `_') [`:' Type] ValDef(_, id, tpe, EmptyTree)
Expand Down
1 change: 1 addition & 0 deletions dottydoc/test/BaseTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ trait DottyTest {
val ctx = base.initialCtx.fresh
ctx.setSetting(ctx.settings.language, List("Scala2"))
ctx.setSetting(ctx.settings.YkeepComments, true)
ctx.setSetting(ctx.settings.YnoInline, true)
base.initialize()(ctx)
ctx
}
Expand Down
3 changes: 3 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ object DottyBuild extends Build {
lazy val dotty = project.in(file(".")).
dependsOn(`dotty-interfaces`).
settings(
// Disable scaladoc generation, makes publishLocal much faster
publishArtifact in packageDoc := false,

overrideScalaVersionSetting,

// set sources to src/, tests to test/ and resources to resources/
Expand Down
8 changes: 8 additions & 0 deletions src/dotty/annotation/internal/Body.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dotty.annotation.internal

import scala.annotation.Annotation

/** The class associated with a `BodyAnnotation`, which indicates
* an inline method's right hand side
*/
final class Body() extends Annotation
6 changes: 6 additions & 0 deletions src/dotty/annotation/internal/InlineParam.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dotty.annotation.internal

import scala.annotation.Annotation

/** An annotation produced by Namer to indicate an inline parameter */
final class InlineParam() extends Annotation
1 change: 1 addition & 0 deletions src/dotty/tools/dotc/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class Compiler {
new SelectStatic, // get rid of selects that would be compiled into GetStatic
new CollectEntryPoints, // Find classes with main methods
new CollectSuperCalls, // Find classes that are called with super
new DropInlined, // Drop Inlined nodes, since backend has no use for them
new MoveStatics, // Move static methods to companion classes
new LabelDefs), // Converts calls to labels to jumps
List(new GenSJSIR), // Generate .js code
Expand Down
2 changes: 1 addition & 1 deletion src/dotty/tools/dotc/FromTasty.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ object FromTasty extends Driver {
case info: ClassfileLoader =>
info.load(clsd) match {
case Some(unpickler: DottyUnpickler) =>
val List(unpickled) = unpickler.body(readPositions = true)
val List(unpickled) = unpickler.body(ctx.addMode(Mode.ReadPositions))
val unit1 = new CompilationUnit(new SourceFile(clsd.symbol.sourceFile, Seq()))
unit1.tpdTree = unpickled
unit1.unpicklers += (clsd.classSymbol -> unpickler.unpickler)
Expand Down
14 changes: 10 additions & 4 deletions src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
import Decorators._
import language.higherKinds
import collection.mutable.ListBuffer
import util.Attachment
import util.Property

object desugar {
import untpd._

/** Tags a .withFilter call generated by desugaring a for expression.
* Such calls can alternatively be rewritten to use filter.
*/
val MaybeFilter = new Attachment.Key[Unit]
val MaybeFilter = new Property.Key[Unit]

/** Info of a variable in a pattern: The named tree and its type */
private type VarInfo = (NameTree, Tree)
Expand Down Expand Up @@ -607,11 +607,17 @@ object desugar {
* ==>
* def $anonfun(params) = body
* Closure($anonfun)
*
* If `inlineable` is true, tag $anonfun with an @inline annotation.
*/
def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = TypeTree()) =
def makeClosure(params: List[ValDef], body: Tree, tpt: Tree = TypeTree(), inlineable: Boolean)(implicit ctx: Context) = {
var mods = synthetic
if (inlineable)
mods = mods.withAddedAnnotation(New(ref(defn.InlineAnnotType), Nil).withPos(body.pos))
Block(
DefDef(nme.ANON_FUN, Nil, params :: Nil, tpt, body).withMods(synthetic),
DefDef(nme.ANON_FUN, Nil, params :: Nil, tpt, body).withMods(mods),
Closure(Nil, Ident(nme.ANON_FUN), EmptyTree))
}

/** If `nparams` == 1, expand partial function
*
Expand Down
44 changes: 35 additions & 9 deletions src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
case mp => mp
}

/** If tree is a closure, it's body, otherwise tree itself */
def closureBody(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs
case _ => tree
}

/** If this is an application, its function part, stripping all
* Apply nodes (but leaving TypeApply nodes in). Otherwise the tree itself.
*/
Expand Down Expand Up @@ -311,6 +305,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
if (vdef.symbol.flags is Mutable) Impure else exprPurity(vdef.rhs)
case _ =>
Impure
// TODO: It seem like this should be exprPurity(tree)
// But if we do that the repl/vars test break. Need to figure out why that's the case.
}

/** The purity level of this expression.
Expand All @@ -327,13 +323,13 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
case EmptyTree
| This(_)
| Super(_, _)
| Literal(_) =>
| Literal(_)
| Closure(_, _, _) =>
Pure
case Ident(_) =>
refPurity(tree)
case Select(qual, _) =>
refPurity(tree).min(
if (tree.symbol.is(Inline)) Pure else exprPurity(qual))
refPurity(tree).min(exprPurity(qual))
case TypeApply(fn, _) =>
exprPurity(fn)
/*
Expand Down Expand Up @@ -435,6 +431,36 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
}
}

/** Decompose a call fn[targs](vargs_1)...(vargs_n)
* into its constituents (where targs, vargss may be empty)
*/
def decomposeCall(tree: Tree): (Tree, List[Tree], List[List[Tree]]) = tree match {
case Apply(fn, args) =>
val (meth, targs, argss) = decomposeCall(fn)
(meth, targs, argss :+ args)
case TypeApply(fn, targs) =>
val (meth, Nil, Nil) = decomposeCall(fn)
(meth, targs, Nil)
case _ =>
(tree, Nil, Nil)
}

/** An extractor for closures, either contained in a block or standalone.
*/
object closure {
def unapply(tree: Tree): Option[(List[Tree], Tree, Tree)] = tree match {
case Block(_, Closure(env, meth, tpt)) => Some(env, meth, tpt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only correct for closures created by desugar.makeClosure and only for certain phases, we have similar pattern matches in other places that makes similar assumption and I don't like it either, I think ExpandSAMs#transformBlock is the only one which tries to be careful, maybe we could use that here:

case Block(stats @ (fn: DefDef) :: Nil, Closure(_, fnRef, tpt)) if fnRef.symbol == fn.symbol =>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this one. The question is, how should closures in other blocks be categorized? Is that still a closure or something else? For the moment I'd leave as is.

case Closure(env, meth, tpt) => Some(env, meth, tpt)
case _ => None
}
}

/** If tree is a closure, its body, otherwise tree itself */
def closureBody(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
case Block((meth @ DefDef(nme.ANON_FUN, _, _, _, _)) :: Nil, Closure(_, _, _)) => meth.rhs
case _ => tree
}

/** The variables defined by a pattern, in reverse order of their appearance. */
def patVars(tree: Tree)(implicit ctx: Context): List[Symbol] = {
val acc = new TreeAccumulator[List[Symbol]] {
Expand Down
16 changes: 11 additions & 5 deletions src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,20 @@ final class TreeTypeMap(
case ddef @ DefDef(name, tparams, vparamss, tpt, _) =>
val (tmap1, tparams1) = transformDefs(ddef.tparams)
val (tmap2, vparamss1) = tmap1.transformVParamss(vparamss)
cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs))
val res = cpy.DefDef(ddef)(name, tparams1, vparamss1, tmap2.transform(tpt), tmap2.transform(ddef.rhs))
res.symbol.transformAnnotations {
case ann: BodyAnnotation => ann.derivedAnnotation(res.rhs)
case ann => ann
}
res
case blk @ Block(stats, expr) =>
val (tmap1, stats1) = transformDefs(stats)
val expr1 = tmap1.transform(expr)
cpy.Block(blk)(stats1, expr1)
case inlined @ Inlined(call, bindings, expanded) =>
val (tmap1, bindings1) = transformDefs(bindings)
val expanded1 = tmap1.transform(expanded)
cpy.Inlined(inlined)(call, bindings1, expanded1)
case cdef @ CaseDef(pat, guard, rhs) =>
val tmap = withMappedSyms(patVars(pat))
val pat1 = tmap.transform(pat)
Expand Down Expand Up @@ -127,10 +136,7 @@ final class TreeTypeMap(

def apply[ThisTree <: tpd.Tree](tree: ThisTree): ThisTree = transform(tree).asInstanceOf[ThisTree]

def apply(annot: Annotation): Annotation = {
val tree1 = apply(annot.tree)
if (tree1 eq annot.tree) annot else ConcreteAnnotation(tree1)
}
def apply(annot: Annotation): Annotation = annot.derivedAnnotation(apply(annot.tree))

/** The current tree map composed with a substitution [from -> to] */
def withSubstitution(from: List[Symbol], to: List[Symbol]): TreeTypeMap =
Expand Down
34 changes: 31 additions & 3 deletions src/dotty/tools/dotc/ast/Trees.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import collection.immutable.IndexedSeq
import collection.mutable.ListBuffer
import parsing.Tokens.Token
import printing.Printer
import util.{Stats, Attachment, DotClass}
import util.{Stats, Attachment, Property, DotClass}
import annotation.unchecked.uncheckedVariance
import language.implicitConversions
import parsing.Scanners.Comment
Expand All @@ -30,8 +30,8 @@ object Trees {
/** The total number of created tree nodes, maintained if Stats.enabled */
@sharable var ntrees = 0

/** Attachment key for trees with documentation strings attached */
val DocComment = new Attachment.Key[Comment]
/** Property key for trees with documentation strings attached */
val DocComment = new Property.Key[Comment]

@sharable private var nextId = 0 // for debugging

Expand Down Expand Up @@ -503,6 +503,25 @@ object Trees {
override def toString = s"JavaSeqLiteral($elems, $elemtpt)"
}

/** A tree representing inlined code.
*
* @param call The original call that was inlined
* @param bindings Bindings for proxies to be used in the inlined code
* @param expansion The inlined tree, minus bindings.
*
* The full inlined code is equivalent to
*
* { bindings; expansion }
*
* The reason to keep `bindings` separate is because they are typed in a
* different context: `bindings` represent the arguments to the inlined
* call, whereas `expansion` represents the body of the inlined function.
*/
case class Inlined[-T >: Untyped] private[ast] (call: tpd.Tree, bindings: List[MemberDef[T]], expansion: Tree[T])
extends Tree[T] {
type ThisTree[-T >: Untyped] = Inlined[T]
}

/** A type tree that represents an existing or inferred type */
case class TypeTree[-T >: Untyped] private[ast] (original: Tree[T])
extends DenotingTree[T] with TypTree[T] {
Expand Down Expand Up @@ -797,6 +816,7 @@ object Trees {
type Try = Trees.Try[T]
type SeqLiteral = Trees.SeqLiteral[T]
type JavaSeqLiteral = Trees.JavaSeqLiteral[T]
type Inlined = Trees.Inlined[T]
type TypeTree = Trees.TypeTree[T]
type SingletonTypeTree = Trees.SingletonTypeTree[T]
type AndTypeTree = Trees.AndTypeTree[T]
Expand Down Expand Up @@ -939,6 +959,10 @@ object Trees {
case tree: SeqLiteral if (elems eq tree.elems) && (elemtpt eq tree.elemtpt) => tree
case _ => finalize(tree, untpd.SeqLiteral(elems, elemtpt))
}
def Inlined(tree: Tree)(call: tpd.Tree, bindings: List[MemberDef], expansion: Tree)(implicit ctx: Context): Inlined = tree match {
case tree: Inlined if (call eq tree.call) && (bindings eq tree.bindings) && (expansion eq tree.expansion) => tree
case _ => finalize(tree, untpd.Inlined(call, bindings, expansion))
}
def TypeTree(tree: Tree)(original: Tree): TypeTree = tree match {
case tree: TypeTree if original eq tree.original => tree
case _ => finalize(tree, untpd.TypeTree(original))
Expand Down Expand Up @@ -1083,6 +1107,8 @@ object Trees {
cpy.Try(tree)(transform(block), transformSub(cases), transform(finalizer))
case SeqLiteral(elems, elemtpt) =>
cpy.SeqLiteral(tree)(transform(elems), transform(elemtpt))
case Inlined(call, bindings, expansion) =>
cpy.Inlined(tree)(call, transformSub(bindings), transform(expansion))
case TypeTree(original) =>
tree
case SingletonTypeTree(ref) =>
Expand Down Expand Up @@ -1185,6 +1211,8 @@ object Trees {
this(this(this(x, block), handler), finalizer)
case SeqLiteral(elems, elemtpt) =>
this(this(x, elems), elemtpt)
case Inlined(call, bindings, expansion) =>
this(this(x, bindings), expansion)
case TypeTree(original) =>
x
case SingletonTypeTree(ref) =>
Expand Down
Loading