Skip to content

Inline traits for specialization in Scala 3 #17329

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

Closed
wants to merge 106 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
56c508b
Allow parsing of inline trait, update printer
timotheeandres Feb 24, 2023
5ffb63e
Implement phase 1 of inlining
timotheeandres Feb 28, 2023
966f12d
Implement phase 2 of inlining
timotheeandres Feb 28, 2023
3c4b310
Use inlining capabilities to inline body of defs
timotheeandres Mar 2, 2023
810dcb6
Improve inlining of traits
timotheeandres Mar 9, 2023
7531239
Add atomic tests for inline traits
timotheeandres Mar 23, 2023
f01f90d
Import Nicolas' work
timotheeandres Mar 28, 2023
567d555
Avoid generating accessor fields for inline traits
timotheeandres Mar 28, 2023
e572676
Use parent span for inlined code
timotheeandres Mar 30, 2023
61516a1
Blacklist inline trait tests due to pickling
timotheeandres Mar 30, 2023
2a077cc
Add benchmark for toy version of Numeric
timotheeandres Apr 3, 2023
8b3437f
Delete by-name parameter tests
timotheeandres Apr 4, 2023
b53f142
Revert "Use parent span for inlined code"
timotheeandres Apr 4, 2023
cd14169
Forbid var in inline traits for now
timotheeandres Apr 4, 2023
e167b96
Add override modifier to param accessors
timotheeandres Apr 4, 2023
e382e75
Forbid using/implicit parameters for now
timotheeandres Apr 4, 2023
ab2c439
Fix typo in type bound
timotheeandres Apr 4, 2023
fdfbe26
Multiple files tests, quick fix of span
timotheeandres Apr 6, 2023
e4e42ae
Improve benchmark, make adding implementations easier
timotheeandres Apr 6, 2023
5866057
Add specialized and inline trait matrices for benchmark
timotheeandres Apr 13, 2023
8c84089
Fix issue with generic type in signature
timotheeandres Apr 13, 2023
4d981af
Import modifications by Nicolas
nicolasstucki Apr 13, 2023
6b02d82
Rework and fix tests
timotheeandres Apr 14, 2023
67173de
Make fields private again
timotheeandres Apr 14, 2023
a516748
Fix type issue between untpd and tpd
timotheeandres Apr 14, 2023
f568ef8
Add tests with manual override
timotheeandres Apr 14, 2023
bd94dc6
Simplify type argument substitution in inline methods
nicolasstucki Apr 14, 2023
fd14025
Refactor creation of inlined symbols
nicolasstucki Apr 14, 2023
c06a501
Only call `inline` on rhs
nicolasstucki Apr 14, 2023
fa53620
Perform misc. changes on tests
timotheeandres Apr 17, 2023
59feb3f
Only allow override final if member is synthetic
timotheeandres Apr 17, 2023
2804dfd
Prevent generation of setters in inline traits
timotheeandres Apr 17, 2023
8b4741b
Don't generate members if they are overridden by user
timotheeandres Apr 17, 2023
59d6221
Fix type params not being replaced in RHS
timotheeandres Apr 18, 2023
b762cc9
Clean up InlineParentTrait
timotheeandres Apr 18, 2023
4bf1c76
Compute overriden symbols only once
timotheeandres Apr 20, 2023
e92c7b5
Factorize code to know what to inline from inline trait
timotheeandres Apr 21, 2023
c676689
Allow inlining of deferred defs
timotheeandres Apr 21, 2023
b9a81b1
Clean up example 4, make version without inner class
timotheeandres Apr 21, 2023
026212f
Update inner class tests
timotheeandres Apr 21, 2023
76e5e9a
Move special expansion cases in inlining methods
timotheeandres Apr 24, 2023
a4fd776
Create InlineTreeMap, make helper function for param accessors
timotheeandres Apr 24, 2023
334b5d3
Make accessor values functions tailrec
timotheeandres Apr 24, 2023
f1aa33e
Implement grandparent inline traits, fix parameters shadowing
timotheeandres Apr 24, 2023
2d20a79
Clean up code to get defs to inline
timotheeandres Apr 26, 2023
fcb2279
Start moving code from Typer
timotheeandres Apr 26, 2023
84a1682
Fix tests/pos/inline-trait-multiple-stages-generic-defs
nicolasstucki Apr 26, 2023
e13a71f
Pass overridden decls when expanding
timotheeandres Apr 26, 2023
59bee43
Remove pickling test blacklist
timotheeandres Apr 26, 2023
845c00b
Move trait inlining into Inlining phase
timotheeandres Apr 26, 2023
3d162cb
Implement ancestors inline traits without term args
timotheeandres Apr 27, 2023
50b6743
Disable test with inner class
timotheeandres Apr 27, 2023
34f77f6
Ensure inline traits have same extends precedence as normal traits
timotheeandres Apr 27, 2023
d605bc5
Partially implement inner traits
timotheeandres Apr 28, 2023
9e26b35
Use typeRef on ctx.owner
timotheeandres Apr 28, 2023
6523fcc
Split symbol inlining method by case
timotheeandres May 8, 2023
bcb6702
Improve checks in phases
timotheeandres May 10, 2023
e3e5582
Remove RHS of definitions in inline traits
timotheeandres May 10, 2023
c9ec223
Add tests with macros (unstable)
timotheeandres May 10, 2023
08e2689
Fix owner of bodies to their rightful symbols
timotheeandres May 10, 2023
5348868
Add more tests
timotheeandres May 10, 2023
060f5ab
Inline code of thisType at sole call site
timotheeandres May 10, 2023
ffe94e8
Forbid defining inline traits inside inline traits
timotheeandres May 11, 2023
67d8b1e
Enable inheritance tests
timotheeandres May 11, 2023
fde0c55
Check if owner is inline trait last
timotheeandres May 12, 2023
086f0b9
Use proper thisType, add coords to inlinedSym
timotheeandres May 12, 2023
2fc66ac
Extract param accessors code into helper class
timotheeandres May 16, 2023
686aac0
Move trait-related code to InlineParentTrait
timotheeandres May 16, 2023
78077a4
Add missing context to expandStat, refactor code
timotheeandres May 23, 2023
2172d03
Refactor Inlining for clarity
timotheeandres May 23, 2023
3f749f1
Factorize code for new inner class names
timotheeandres May 23, 2023
5570b25
Remove last refs to inline trait from Inliner
timotheeandres May 23, 2023
829f9eb
Call super before matching in Tree-/TypeMap
timotheeandres May 23, 2023
a1bc61f
Improve class symbol inlining
timotheeandres May 23, 2023
5226450
Prevent creating new accessor names for inner class' params
timotheeandres May 23, 2023
728d837
Do not add override flag to inner class-like type params
timotheeandres May 23, 2023
2392575
Remove incorrect parent, TODO add correct one
timotheeandres May 23, 2023
c4f13af
Add proper type bound to generated type
timotheeandres May 23, 2023
0b6ec5e
Register class-like symbol to be replaced by inliner
timotheeandres May 23, 2023
6075cd3
Forbid term params for inline traits
timotheeandres May 24, 2023
74aaba9
Create vals for child type and child tree
timotheeandres May 25, 2023
9514ccd
Add proper parent to inner class info
timotheeandres May 25, 2023
a5b53f8
Make function to inline just rhs
timotheeandres May 25, 2023
6fc5bd9
Handle inlining of statements in inline trait body
timotheeandres May 25, 2023
8a756d2
Add tests for inner traits
timotheeandres May 30, 2023
39e57f2
Remove FIXME along with info mapping
timotheeandres May 31, 2023
d7ada60
Add test for anonymous class extending inline trait
timotheeandres Jun 1, 2023
4b99869
Rename param for clarity
timotheeandres Jun 1, 2023
746e677
Create helper methods for inline trait rewriting
timotheeandres Jun 1, 2023
d896688
Strip parents of inner class from concrete elements
timotheeandres Jun 1, 2023
b1eec85
Add Synthetic flag to new trait and type
timotheeandres Jun 1, 2023
e13d3c4
Adapt body of child to point to inlined members
timotheeandres Jun 1, 2023
34a5567
Use wildcard for default var value in benchmark
timotheeandres Jun 5, 2023
5a0339b
Add Pair to benchmark
timotheeandres Jun 5, 2023
b1e16ab
Manual specialization, remove unused toTuple
timotheeandres Jun 6, 2023
cb95383
Add boxing benchmark for report
timotheeandres Jun 14, 2023
2784d54
Move inline trait inlining to its own phase
timotheeandres Jun 5, 2023
5c82ee0
Add simple test for inner class
timotheeandres Jun 16, 2023
6e8a489
Rework benchmark files for report
timotheeandres Jul 4, 2023
7c82e3d
Remove target name for inlined inner class
timotheeandres Jul 4, 2023
fd737ea
Restrict non-local private fields
timotheeandres Jul 4, 2023
7e2952c
Forbid user from overriding vars
timotheeandres Jul 4, 2023
f6e171b
Add tests for constructor arguments with side effects
timotheeandres Jul 4, 2023
102269e
Improve error message, remove unused method
timotheeandres Jul 4, 2023
a557940
Allow overriding opaque aliases for inline traits
timotheeandres Jul 4, 2023
17e17bc
Let compiler complain if deferred member isn't implemented
timotheeandres Jul 4, 2023
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
Prev Previous commit
Next Next commit
Import Nicolas' work
Allows for private trait parameters and private inner classes
  • Loading branch information
timotheeandres committed Jun 16, 2023
commit f01f90db1d907fa6256d89776bcdec5afc397336
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/ast/TreeTypeMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,7 @@ class TreeTypeMap(
case ddef @ DefDef(name, paramss, tpt, _) =>
val (tmap1, paramss1) = transformAllParamss(paramss)
val res = cpy.DefDef(ddef)(name, paramss1, tmap1.transform(tpt), tmap1.transform(ddef.rhs))
if tree.symbol.owner.isInlineTrait then
res.symbol.info = mapType(res.symbol.info) // FIXME inline traits' info doesn't get mapped
res.symbol.info = mapType(res.symbol.info) // FIXME inline traits' info doesn't get mapped
res.symbol.setParamssFromDefs(paramss1)
res.symbol.transformAnnotations {
case ann: BodyAnnotation => ann.derivedAnnotation(transform(ann.tree))
Expand Down
17 changes: 0 additions & 17 deletions compiler/src/dotty/tools/dotc/inlines/Inliner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -579,23 +579,6 @@ class Inliner(val call: tpd.Tree)(using Context):
}
},
treeMap = {
case tree: (DefDef | ValDef | TypeDef) if inlinedMethod.is(Trait) && tree.symbol.owner == inlinedMethod =>
val sym = tree.symbol
val inlinedSym = sym.copy(owner = ctx.owner, flags = sym.flags | Override)
inlinedSym.entered // Should this be entered here? Or after inlining process has succeeded

tree match {
case tree: DefDef =>
def rhsFun(paramss: List[List[Tree]]): Tree =
val oldParamSyms = tree.paramss.flatten.map(_.symbol)
val newParamSyms = paramss.flatten.map(_.symbol)
tree.rhs.subst(oldParamSyms, newParamSyms)
tpd.DefDef(inlinedSym.asTerm, rhsFun).withSpan(tree.span)
case tree: ValDef =>
tpd.ValDef(inlinedSym.asTerm, tree.rhs).withSpan(tree.span)
case tree: TypeDef =>
tpd.TypeDef(inlinedSym.asType).withSpan(tree.span)
}
case tree: This =>
tree.tpe match {
case thistpe: ThisType =>
Expand Down
64 changes: 63 additions & 1 deletion compiler/src/dotty/tools/dotc/inlines/Inlines.scala
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,69 @@ object Inlines:
import Inlines.*

def expandDefs(): List[Tree] =
val argsMap = parent match
case Apply(_, args) =>
val MethodType(paramNames) = parent.symbol.info: @unchecked
paramNames.zip(args).toMap
case _ => Map.empty

val Block(stats, _) = Inlines.bodyToInline(parentSym): @unchecked
stats.map(stat => inlined(stat)._2)

val stats1 = stats.map { stat =>
val sym = stat.symbol
stat match
case tree: ValDef if sym.is(ParamAccessor) =>
val vdef = cloneValDef(tree)
vdef.symbol.resetFlag(ParamAccessor)
cpy.ValDef(vdef)(rhs = argsMap(sym.name.asTermName))
case stat: ValDef =>
val vdef = cloneValDef(stat)
if !sym.is(Private) then vdef.symbol.setFlag(Override)
cpy.ValDef(vdef)() // TODO keep rhs? Can we do a single ValOrDefDef case using cloneStat?
case stat: DefDef =>
val ddef = cloneDefDef(stat)
if !sym.is(Private) then ddef.symbol.setFlag(Override)
ddef
case stat @ TypeDef(_, impl: Template) =>
cloneClass(stat, impl)
case stat: TypeDef =>
val tdef = cloneTypeDef(stat)
tdef.symbol.setFlag(Override)
cpy.TypeDef(tdef)()
}
stats1.map(stat => inlined(stat)._2)

private def cloneClass(clDef: TypeDef, impl: Template)(using Context): TypeDef =
val inlinedCls: ClassSymbol =
val ClassInfo(prefix, cls, declaredParents, scope, selfInfo) = clDef.symbol.info: @unchecked
val inlinedInfo = ClassInfo(prefix, cls, declaredParents, Scopes.newScope, selfInfo) // TODO adapt parents
clDef.symbol.copy(owner = ctx.owner, info = inlinedInfo).entered.asClass
val (constr, body) = inContext(ctx.withOwner(inlinedCls)) {
(cloneDefDef(impl.constr), impl.body.map(cloneStat))
}
tpd.ClassDefWithParents(inlinedCls, constr, impl.parents, body).withSpan(clDef.span) // TODO adapt parents

private def cloneStat(tree: Tree)(using Context): Tree = tree match
case tree: DefDef => cloneDefDef(tree)
case tree: ValDef => cloneValDef(tree)
// TODO case stat @ TypeDef(_, impl: Template) => cloneClass(stat, impl)
// TODO case tree: TypeDef => cloneTypeDef(tree)

private def cloneDefDef(ddef: DefDef)(using Context): DefDef =
val inlinedSym = ddef.symbol.copy(owner = ctx.owner).entered
def rhsFun(paramss: List[List[Tree]]): Tree =
val oldParamSyms = ddef.paramss.flatten.map(_.symbol)
val newParamSyms = paramss.flatten.map(_.symbol)
ddef.rhs.subst(oldParamSyms, newParamSyms) // TODO clone local classes?
tpd.DefDef(inlinedSym.asTerm, rhsFun).withSpan(ddef.span)

private def cloneValDef(vdef: ValDef)(using Context): ValDef =
val inlinedSym = vdef.symbol.copy(owner = ctx.owner).entered
tpd.ValDef(inlinedSym.asTerm, vdef.rhs).withSpan(vdef.span) // TODO clone local classes?

private def cloneTypeDef(tdef: TypeDef)(using Context): TypeDef =
val inlinedSym = tdef.symbol.copy(owner = ctx.owner).entered
tpd.TypeDef(inlinedSym.asType).withSpan(tdef.span)

end InlineParentTrait
end Inlines
17 changes: 12 additions & 5 deletions tests/pos/inline-trait-1-simple-trait.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ inline trait A:
type X = String

val x: Int = 3
val y: Int = x + 1
val y: Int = x + z
private val z: Int = 1

def f: Int = f
def f: Int = g
def f(x: Int): Int = x
def f[T](x: T): Int = 2

private def g = 1

def xx: X = "foo".asInstanceOf[X]
end A

Expand All @@ -16,12 +19,16 @@ class B extends A:
<generated> override type X = String

<generated> override val x: Int = 3
<generated> override val y: Int = x + 1
<generated> override val y: Int = this.x.+(this.z)

<generated> private[this] val z: Int = 1

<generated> override def f: Int = 2
<generated> override def f(x: Int): Int = 2
<generated> override def f: Int = this.g
<generated> override def f(x: Int): Int = x
<generated> override def f[T](x: T): Int = 2

<generated> private[this] def g: Int = 1

<generated> override def xx: X = "foo".asInstanceOf[X]
*/
end B
15 changes: 15 additions & 0 deletions tests/pos/inline-trait-3-trait-params.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
inline trait A(a: Int):
def f: Int = a
def g(b: Int): Int = a + b
end A

class B extends A(4):
// FIXME: Should not generate second field for A.a (probably in the memoize phase). `B.A$$a` could point to the `a` we already have.
// Alternative: remove the field and defs from `A`.

/*
<generated> private val a: Int = 4
<generated> override def f: Int = this.a
<generated> override def g(x: Int): Int = this.a.+(b)
*/
end B
28 changes: 28 additions & 0 deletions tests/pos/inline-trait-4-inner-class.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
inline trait Options[T]:
// FIXME: remove original class definition from inline trait to allow public classes
private trait Option:
def get: T
// FIXME: support constructor parameter
// FIXME: support specialized parents
private class Some://(x: T): // extends Option
def get: T = ??? // x
// FIXME: support specialized modules
// private object None // extends Option
// def get: T = throw new NoSuchElementException("None.get")

// FIXME: specialize reference to Option and Some
// def option(value: T): Option = new Some//(value)
end Options

object IntOptions extends Options[Int]:
/*
<generated> trait Option:
def get: Int
<generated> class Some(x: Int) extends Option
def get: Int = x
<generated> object None extends Option
def get: Int = throw new NoSuchElementException("None.get")

<generated> def option(value: Int): Option = new Some(value)
*/
end IntOptions