Skip to content

Commit

Permalink
wip - trait constructors
Browse files Browse the repository at this point in the history
  • Loading branch information
bishabosha committed Oct 4, 2024
1 parent fba2445 commit 91a2304
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 19 deletions.
3 changes: 2 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/Constructors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ class Constructors extends MiniPhase with IdentityDenotTransformer { thisPhase =
val setter =
if (symSetter.exists) symSetter
else sym.accessorNamed(Mixin.traitSetterName(sym.asTerm))
constrStats += Apply(ref(setter), intoConstr(stat.rhs, sym).withSpan(stat.span) :: Nil)
if setter.exists then
constrStats += Apply(ref(setter), intoConstr(stat.rhs, sym).withSpan(stat.span) :: Nil)
clsStats += cpy.DefDef(stat)(rhs = EmptyTree)
case DefDef(nme.CONSTRUCTOR, ((outerParam @ ValDef(nme.OUTER, _, _)) :: _) :: Nil, _, _) =>
clsStats += mapOuter(outerParam.symbol).transform(stat)
Expand Down
7 changes: 6 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/Mixin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,12 @@ class Mixin extends MiniPhase with SymTransformer { thisPhase =>
if (sym.is(Accessor, butNot = Deferred) && ownerIsTrait) {
val sym1 =
if (sym.is(Lazy) || sym.symbol.isConstExprFinalVal) sym
else sym.copySymDenotation(initFlags = sym.flags &~ (ParamAccessor | Inline) | Deferred)
else
if sym.hasAnnotation(defn.UnrollAnnot) then
???
sym.copySymDenotation(initFlags = sym.flags &~ (ParamAccessor | Inline))
else
sym.copySymDenotation(initFlags = sym.flags &~ (ParamAccessor | Inline) | Deferred)
sym1.ensureNotPrivate
}
else if sym.isAllOf(ModuleClass | Private) && ownerIsTrait then
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
report.error("Unrolled method must be final and concrete", method.srcPos)
res = false
val isCtor = method.isConstructor
if isCtor && method.owner.is(Trait) then
report.error("implementation restriction: Unrolled method cannot be a trait constructor", method.srcPos)
res = false
// if isCtor && method.owner.is(Trait) then
// report.error("implementation restriction: Unrolled method cannot be a trait constructor", method.srcPos)
// res = false
if !(isCtor || method.is(Final) || method.owner.is(ModuleClass)) then
report.error(s"Unrolled method ${method} must be final", method.srcPos)
res = false
Expand Down
26 changes: 24 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,25 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {
).setDefTree
}

def generateSyntheticDefs(tree: Tree, compute: ComputeIndicies)(using Context): Option[(Symbol, Option[Symbol], Seq[DefDef])] = tree match {
def generateSyntheticDefs(tree: Tree, compute: ComputeIndicies)(using Context): Option[(Symbol, Option[Symbol], Seq[ValOrDefDef])] = tree match {
case valdef: ValDef if valdef.symbol.is(ParamAccessor) && valdef.symbol.owner.is(Trait) =>
val ctor = valdef.symbol.owner.primaryConstructor
compute(ctor) match {
case Nil => None
case Seq((paramClauseIndex, annotationIndices)) =>
val defaultParams = ctor.paramSymss(paramClauseIndex).drop(annotationIndices.head)
// assert(firstAnnotated.hasAnnotation(defn.UnrollAnnot))
// report.warning(i"TODO: implemet for $defaultParams")

if defaultParams.exists(_.name == valdef.name) then
val rhs = ref(defn.ScalaPredefModule).select(defn.Predef_undefined).ensureApplied
val valdef0 = cpy.ValDef(valdef)(rhs = rhs)
Some((valdef.symbol, Some(valdef.symbol), Seq(valdef0)))
else
None
case multiple => sys.error("Cannot have multiple parameter lists containing `@unroll` annotation")
}

case defdef: DefDef if defdef.paramss.nonEmpty =>
import dotty.tools.dotc.core.NameOps.isConstructorName

Expand All @@ -276,6 +294,8 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {

val isCaseFromProduct = defdef.name.toString == "fromProduct" && defdef.symbol.owner.companionClass.is(CaseClass)

val isTraitConstructor = defdef.name.isConstructorName && defdef.symbol.owner.is(Trait)

val annotated =
if (isCaseCopy) defdef.symbol.owner.primaryConstructor
else if (isCaseApply) defdef.symbol.owner.companionClass.primaryConstructor
Expand All @@ -286,7 +306,9 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {
case Nil => None
case Seq((paramClauseIndex, annotationIndices)) =>
val paramCount = annotated.paramSymss(paramClauseIndex).size
if isCaseFromProduct then
if isTraitConstructor then
None // we must not generate forwarder methods for trait constructors
else if isCaseFromProduct then
Some((defdef.symbol, Some(defdef.symbol), Seq(generateFromProduct(annotationIndices, paramCount, defdef))))
else
val (generatedDefs, _) =
Expand Down
4 changes: 0 additions & 4 deletions tests/neg/unroll-traitConstructor.check

This file was deleted.

8 changes: 0 additions & 8 deletions tests/neg/unroll-traitConstructor.scala

This file was deleted.

9 changes: 9 additions & 0 deletions tests/run/unroll-traitConstructor/Test_3.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//> using options -experimental

@main def Test: Unit =
val bar = Bar(1, "abc", 2, 20)
assert(bar.res == 23)

val foo = Foo(1, "abc", 2)
assert(foo.res == 13)
end Test
8 changes: 8 additions & 0 deletions tests/run/unroll-traitConstructor/Unroll_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//> using options -experimental

// import scala.annotation.unroll

trait Unrolled(x: Int, s: String)(y: Int):
def res: Int = x + y

class Foo(x: Int, s: String, y: Int) extends Unrolled(x, s)(y)
8 changes: 8 additions & 0 deletions tests/run/unroll-traitConstructor/Unroll_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//> using options -experimental

import scala.annotation.unroll

trait Unrolled(x: Int, s: String)(y: Int, @unroll z: Int = 10):
def res: Int = x + y + z

class Bar(x: Int, s: String, y: Int, z: Int) extends Unrolled(x, s)(y, z)

0 comments on commit 91a2304

Please sign in to comment.