Skip to content

Commit 93599be

Browse files
authored
Merge pull request #1226 from dotty-staging/static-fixes
Multiple fixes to @static
2 parents 914d465 + 3c93c5c commit 93599be

17 files changed

+174
-34
lines changed

src/dotty/runtime/LazyVals.scala

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,24 @@ object LazyVals {
1010

1111
final val BITS_PER_LAZY_VAL = 2L
1212
final val LAZY_VAL_MASK = 3L
13+
final val debug = false
1314

14-
@inline def STATE(cur: Long, ord: Int) = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
15+
@inline def STATE(cur: Long, ord: Int) = {
16+
val r = (cur >> (ord * BITS_PER_LAZY_VAL)) & LAZY_VAL_MASK
17+
if (debug)
18+
println(s"STATE($cur, $ord) = $r")
19+
r
20+
}
1521
@inline def CAS(t: Object, offset: Long, e: Long, v: Int, ord: Int) = {
22+
if (debug)
23+
println(s"CAS($t, $offset, $e, $v, $ord)")
1624
val mask = ~(LAZY_VAL_MASK << ord * BITS_PER_LAZY_VAL)
1725
val n = (e & mask) | (v << (ord * BITS_PER_LAZY_VAL))
1826
compareAndSet(t, offset, e, n)
1927
}
2028
@inline def setFlag(t: Object, offset: Long, v: Int, ord: Int) = {
29+
if (debug)
30+
println(s"setFlag($t, $offset, $v, $ord)")
2131
var retry = true
2232
while (retry) {
2333
val cur = get(t, offset)
@@ -35,6 +45,8 @@ object LazyVals {
3545
}
3646
}
3747
@inline def wait4Notification(t: Object, offset: Long, cur: Long, ord: Int) = {
48+
if (debug)
49+
println(s"wait4Notification($t, $offset, $cur, $ord)")
3850
var retry = true
3951
while (retry) {
4052
val cur = get(t, offset)
@@ -51,7 +63,11 @@ object LazyVals {
5163
}
5264

5365
@inline def compareAndSet(t: Object, off: Long, e: Long, v: Long) = unsafe.compareAndSwapLong(t, off, e, v)
54-
@inline def get(t: Object, off: Long) = unsafe.getLongVolatile(t, off)
66+
@inline def get(t: Object, off: Long) = {
67+
if (debug)
68+
println(s"get($t, $off)")
69+
unsafe.getLongVolatile(t, off)
70+
}
5571

5672
val processors: Int = java.lang.Runtime.getRuntime.availableProcessors()
5773
val base: Int = 8 * processors * processors
@@ -68,7 +84,12 @@ object LazyVals {
6884
monitors(id)
6985
}
7086

71-
@inline def getOffset(clz: Class[_], name: String) = unsafe.objectFieldOffset(clz.getDeclaredField(name))
87+
@inline def getOffset(clz: Class[_], name: String) = {
88+
val r = unsafe.objectFieldOffset(clz.getDeclaredField(name))
89+
if (debug)
90+
println(s"getOffset($clz, $name) = $r")
91+
r
92+
}
7293

7394
object Names {
7495
final val state = "STATE"

src/dotty/tools/backend/jvm/DottyBackendInterface.scala

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import scala.collection.generic.Clearable
1212
import scala.collection.mutable
1313
import scala.reflect.ClassTag
1414
import scala.reflect.internal.util.WeakHashSet
15-
import scala.reflect.io.{Directory, PlainDirectory, AbstractFile}
15+
import scala.reflect.io.{AbstractFile, Directory, PlainDirectory}
1616
import scala.tools.asm.{AnnotationVisitor, ClassVisitor, FieldVisitor, MethodVisitor}
1717
import scala.tools.nsc.backend.jvm.{BCodeHelpers, BackendInterface}
1818
import dotty.tools.dotc.core._
@@ -24,13 +24,16 @@ import Symbols._
2424
import Denotations._
2525
import Phases._
2626
import java.lang.AssertionError
27-
import dotty.tools.dotc.util.{Positions, DotClass}
27+
28+
import dotty.tools.dotc.util.{DotClass, Positions}
2829
import Decorators._
2930
import tpd._
31+
3032
import scala.tools.asm
3133
import NameOps._
3234
import StdNames.nme
3335
import NameOps._
36+
import dotty.tools.dotc.core
3437

3538
class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context) extends BackendInterface{
3639
type Symbol = Symbols.Symbol
@@ -633,7 +636,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context
633636
toDenot(sym)(shiftedContext).isStatic(shiftedContext)
634637
}
635638

636-
def isStaticConstructor: Boolean = isStaticMember && isClassConstructor
639+
def isStaticConstructor: Boolean = (isStaticMember && isClassConstructor) || (sym.name eq core.Names.STATIC_CONSTRUCTOR)
637640

638641

639642
// navigation
@@ -716,7 +719,7 @@ class DottyBackendInterface(outputDirectory: AbstractFile)(implicit ctx: Context
716719
toDenot(sym).info.decls.filter(p => p.isTerm && !p.is(Flags.Method)).toList
717720
}
718721
def methodSymbols: List[Symbol] =
719-
for (f <- toDenot(sym).info.decls.toList if !f.isMethod && f.isTerm && !f.isModule) yield f
722+
for (f <- toDenot(sym).info.decls.toList if f.isMethod && f.isTerm && !f.isModule) yield f
720723
def serialVUID: Option[Long] = None
721724

722725

src/dotty/tools/dotc/Compiler.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class Compiler {
9191
new RestoreScopes), // Repair scopes rendered invalid by moving definitions in prior phases of the group
9292
List(new ExpandPrivate, // Widen private definitions accessed from nested classes
9393
new CollectEntryPoints, // Find classes with main methods
94+
new MoveStatics, // Move static methods to companion classes
9495
new LabelDefs), // Converts calls to labels to jumps
9596
List(new GenSJSIR), // Generate .js code
9697
List(new GenBCode) // Generate JVM bytecode

src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ object NameOps {
6363
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]
6464

6565
def isConstructorName = name == CONSTRUCTOR || name == TRAIT_CONSTRUCTOR
66+
def isStaticConstructorName = name == STATIC_CONSTRUCTOR
6667
def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX
6768
def isImplClassName = name endsWith IMPL_CLASS_SUFFIX
6869
def isLocalDummyName = name startsWith LOCALDUMMY_PREFIX

src/dotty/tools/dotc/core/Names.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ object Names {
335335

336336
// can't move CONSTRUCTOR/EMPTY_PACKAGE to `nme` because of bootstrap failures in `encode`.
337337
val CONSTRUCTOR = termName("<init>")
338+
val STATIC_CONSTRUCTOR = termName("<clinit>")
338339
val EMPTY_PACKAGE = termName("<empty>")
339340

340341
val dontEncode = Set(CONSTRUCTOR, EMPTY_PACKAGE)

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,10 @@ object SymDenotations {
594594
final def isPrimaryConstructor(implicit ctx: Context) =
595595
isConstructor && owner.primaryConstructor == symbol
596596

597+
/** Does this symbol denote the static constructor of its enclosing class? */
598+
final def isStaticConstructor(implicit ctx: Context) =
599+
name.isStaticConstructorName
600+
597601
/** Is this a subclass of the given class `base`? */
598602
def isSubClass(base: Symbol)(implicit ctx: Context) = false
599603

@@ -1001,7 +1005,7 @@ object SymDenotations {
10011005
if (!canMatchInheritedSymbols) Iterator.empty
10021006
else overriddenFromType(owner.info)
10031007

1004-
/** Returns all all matching symbols defined in parents of the selftype. */
1008+
/** Returns all matching symbols defined in parents of the selftype. */
10051009
final def extendedOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
10061010
if (!canMatchInheritedSymbols) Iterator.empty
10071011
else overriddenFromType(owner.asClass.classInfo.selfType)
@@ -1499,7 +1503,7 @@ object SymDenotations {
14991503

15001504
/** Enter a symbol in given `scope` without potentially replacing the old copy. */
15011505
def enterNoReplace(sym: Symbol, scope: MutableScope)(implicit ctx: Context): Unit = {
1502-
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls))
1506+
require((sym.denot.flagsUNSAFE is Private) || !(this is Frozen) || (scope ne this.unforcedDecls) || sym.hasAnnotation(defn.ScalaStaticAnnot))
15031507
scope.enter(sym)
15041508

15051509
if (myMemberFingerPrint != FingerPrint.unknown)

src/dotty/tools/dotc/transform/CheckStatic.scala

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import TypeUtils._
3232
* is not allowed to inherit classes that define a term member with name `foo`.
3333
* 5. Only `@static` methods and vals are supported in companions of traits.
3434
* Java8 supports those, but not vars, and JavaScript does not have interfaces at all.
35+
* 6. `@static` Lazy vals are currently unsupported.
3536
*/
3637
class CheckStatic extends MiniPhaseTransform { thisTransformer =>
3738
import ast.tpd._
@@ -57,17 +58,18 @@ class CheckStatic extends MiniPhaseTransform { thisTransformer =>
5758
}
5859

5960
val companion = ctx.owner.companionClass
60-
if (!companion.exists) {
61-
ctx.error("object that conatin @static members should have companion class", defn.pos)
62-
}
61+
def clashes = companion.asClass.membersNamed(defn.name)
6362

64-
val clashes = companion.asClass.membersNamed(defn.name)
65-
if (clashes.exists) {
63+
if (!companion.exists) {
64+
ctx.error("object that contains @static members should have companion class", defn.pos)
65+
} else if (clashes.exists) {
6666
ctx.error("companion classes cannot define members with same name as @static member", defn.pos)
67-
}
68-
69-
if (defn.symbol.is(Flags.Mutable) && companion.is(Flags.Trait)) {
70-
ctx.error("Companions of traits cannot define mutable @static fields")
67+
} else if (defn.symbol.is(Flags.Mutable) && companion.is(Flags.Trait)) {
68+
ctx.error("Companions of traits cannot define mutable @static fields", defn.pos)
69+
} else if (defn.symbol.is(Flags.Lazy)) {
70+
ctx.error("Lazy @static fields are not supported", defn.pos)
71+
} else if (defn.symbol.allOverriddenSymbols.nonEmpty) {
72+
ctx.error("@static members cannot override or implement non-static ones", defn.pos)
7173
}
7274
} else hadNonStaticField = hadNonStaticField || defn.isInstanceOf[ValDef]
7375

src/dotty/tools/dotc/transform/Constructors.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
9191
*/
9292
override def checkPostCondition(tree: tpd.Tree)(implicit ctx: Context): Unit = {
9393
tree match {
94-
case tree: ValDef if tree.symbol.exists && tree.symbol.owner.isClass && !tree.symbol.is(Lazy) =>
94+
case tree: ValDef if tree.symbol.exists && tree.symbol.owner.isClass && !tree.symbol.is(Lazy) && !tree.symbol.hasAnnotation(defn.ScalaStaticAnnot) =>
9595
assert(tree.rhs.isEmpty, i"$tree: initializer should be moved to constructors")
9696
case tree: DefDef if !tree.symbol.is(LazyOrDeferred) =>
9797
assert(!tree.rhs.isEmpty, i"unimplemented: $tree")
@@ -181,7 +181,7 @@ class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { th
181181
def splitStats(stats: List[Tree]): Unit = stats match {
182182
case stat :: stats1 =>
183183
stat match {
184-
case stat @ ValDef(name, tpt, _) if !stat.symbol.is(Lazy) =>
184+
case stat @ ValDef(name, tpt, _) if !stat.symbol.is(Lazy) && !stat.symbol.hasAnnotation(defn.ScalaStaticAnnot) =>
185185
val sym = stat.symbol
186186
if (isRetained(sym)) {
187187
if (!stat.rhs.isEmpty && !isWildcardArg(stat.rhs))

src/dotty/tools/dotc/transform/Getters.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Getters extends MiniPhaseTransform with SymTransformer { thisTransform =>
5656
d.is(NoGetterNeeded) ||
5757
d.initial.asInstanceOf[SymDenotation].is(PrivateLocal) && !d.owner.is(Trait) && !isDerivedValueClass(d.owner) && !d.is(Flags.Lazy) ||
5858
d.is(Module) && d.isStatic ||
59+
d.hasAnnotation(defn.ScalaStaticAnnot) ||
5960
d.isSelfSym
6061
if (d.isTerm && (d.is(Lazy) || d.owner.isClass) && d.info.isValueType && !noGetterNeeded) {
6162
val maybeStable = if (d.isStable) Stable else EmptyFlags

src/dotty/tools/dotc/transform/LazyVals.scala

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import dotty.tools.dotc.core.SymDenotations.SymDenotation
2626
import dotty.tools.dotc.core.DenotTransformers.{SymTransformer, IdentityDenotTransformer, DenotTransformer}
2727
import Erasure.Boxing.adaptToType
2828

29-
class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer with NeedsCompanions {
29+
class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer {
3030
import LazyVals._
3131

3232
import tpd._
@@ -49,11 +49,6 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer with Nee
4949
* before this phase starts processing same tree */
5050
override def runsAfter = Set(classOf[Mixin])
5151

52-
def isCompanionNeeded(cls: ClassSymbol)(implicit ctx: Context): Boolean = {
53-
def hasLazyVal(cls: ClassSymbol) = cls.info.decls.exists(_.is(Flags.Lazy))
54-
hasLazyVal(cls) || cls.mixins.exists(hasLazyVal)
55-
}
56-
5752
override def transformDefDef(tree: tpd.DefDef)(implicit ctx: Context, info: TransformerInfo): tpd.Tree =
5853
transformLazyVal(tree)
5954

@@ -341,26 +336,28 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer with Nee
341336
val tpe = x.tpe.widen.resultType.widen
342337
val claz = x.symbol.owner.asClass
343338
val thizClass = Literal(Constant(claz.info))
344-
val companion = claz.companionModule
345339
val helperModule = ctx.requiredModule("dotty.runtime.LazyVals")
346340
val getOffset = Select(ref(helperModule), lazyNme.RLazyVals.getOffset)
347341
var offsetSymbol: TermSymbol = null
348342
var flag: Tree = EmptyTree
349343
var ord = 0
350344

345+
def offsetName(id: Int) = (StdNames.nme.LAZY_FIELD_OFFSET + (if(x.symbol.owner.is(Flags.Module)) "_m_" else "") + id.toString).toTermName
346+
351347
// compute or create appropriate offsetSymol, bitmap and bits used by current ValDef
352-
appendOffsetDefs.get(companion.moduleClass) match {
348+
appendOffsetDefs.get(claz) match {
353349
case Some(info) =>
354350
val flagsPerLong = (64 / dotty.runtime.LazyVals.BITS_PER_LAZY_VAL).toInt
355351
info.ord += 1
356352
ord = info.ord % flagsPerLong
357353
val id = info.ord / flagsPerLong
354+
val offsetById = offsetName(id)
358355
if (ord != 0) { // there are unused bits in already existing flag
359-
offsetSymbol = companion.moduleClass.info.decl((StdNames.nme.LAZY_FIELD_OFFSET + id.toString).toTermName)
356+
offsetSymbol = claz.info.decl(offsetById)
360357
.suchThat(sym => (sym is Flags.Synthetic) && sym.isTerm)
361358
.symbol.asTerm
362359
} else { // need to create a new flag
363-
offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + id.toString).toTermName, Flags.Synthetic, defn.LongType).enteredAfter(this)
360+
offsetSymbol = ctx.newSymbol(claz, offsetById, Flags.Synthetic, defn.LongType).enteredAfter(this)
364361
offsetSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot))
365362
val flagName = (StdNames.nme.BITMAP_PREFIX + id.toString).toTermName
366363
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this)
@@ -370,13 +367,13 @@ class LazyVals extends MiniPhaseTransform with IdentityDenotTransformer with Nee
370367
}
371368

372369
case None =>
373-
offsetSymbol = ctx.newSymbol(companion.moduleClass, (StdNames.nme.LAZY_FIELD_OFFSET + "0").toTermName, Flags.Synthetic, defn.LongType).enteredAfter(this)
370+
offsetSymbol = ctx.newSymbol(claz, offsetName(0), Flags.Synthetic, defn.LongType).enteredAfter(this)
374371
offsetSymbol.addAnnotation(Annotation(defn.ScalaStaticAnnot))
375372
val flagName = (StdNames.nme.BITMAP_PREFIX + "0").toTermName
376373
val flagSymbol = ctx.newSymbol(claz, flagName, containerFlags, defn.LongType).enteredAfter(this)
377374
flag = ValDef(flagSymbol, Literal(Constants.Constant(0L)))
378375
val offsetTree = ValDef(offsetSymbol, getOffset.appliedTo(thizClass, Literal(Constant(flagName.toString))))
379-
appendOffsetDefs += (companion.moduleClass -> new OffsetInfo(List(offsetTree), ord))
376+
appendOffsetDefs += (claz -> new OffsetInfo(List(offsetTree), ord))
380377
}
381378

382379
val containerName = ctx.freshName(x.name.asTermName.lazyLocalName).toTermName
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package dotty.tools.dotc.transform
2+
3+
import dotty.tools.dotc.ast.{Trees, tpd}
4+
import dotty.tools.dotc.core.Annotations.Annotation
5+
import dotty.tools.dotc.core.Contexts.Context
6+
import dotty.tools.dotc.core.DenotTransformers.{InfoTransformer, SymTransformer}
7+
import dotty.tools.dotc.core.SymDenotations.SymDenotation
8+
import dotty.tools.dotc.core.Decorators._
9+
import dotty.tools.dotc.core.NameOps._
10+
import dotty.tools.dotc.core.{Flags, Names}
11+
import dotty.tools.dotc.core.Names.Name
12+
import dotty.tools.dotc.core.Symbols._
13+
import dotty.tools.dotc.core.Types.MethodType
14+
import dotty.tools.dotc.transform.TreeTransforms.{MiniPhaseTransform, TransformerInfo}
15+
16+
/** Move static methods from companion to the class itself */
17+
class MoveStatics extends MiniPhaseTransform with SymTransformer { thisTransformer =>
18+
19+
import tpd._
20+
override def phaseName = "moveStatic"
21+
22+
23+
def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = {
24+
if (sym.hasAnnotation(defn.ScalaStaticAnnot) && sym.owner.is(Flags.Module) && sym.owner.companionClass.exists) {
25+
sym.owner.asClass.delete(sym.symbol)
26+
sym.owner.companionClass.asClass.enter(sym.symbol)
27+
val flags = if (sym.is(Flags.Method)) sym.flags else sym.flags | Flags.Mutable
28+
sym.copySymDenotation(owner = sym.owner.companionClass, initFlags = flags)
29+
}
30+
else sym
31+
}
32+
33+
override def transformStats(trees: List[Tree])(implicit ctx: Context, info: TransformerInfo): List[Tree] = {
34+
if (ctx.owner.is(Flags.Package)) {
35+
val (classes, others) = trees.partition(x => x.isInstanceOf[TypeDef] && x.symbol.isClass)
36+
val pairs = classes.groupBy(_.symbol.name.stripModuleClassSuffix).asInstanceOf[Map[Name, List[TypeDef]]]
37+
38+
def rebuild(orig: TypeDef, newBody: List[Tree]): Tree = {
39+
if (orig eq null) return EmptyTree
40+
41+
val staticFields = newBody.filter(x => x.isInstanceOf[ValDef] && x.symbol.hasAnnotation(defn.ScalaStaticAnnot)).asInstanceOf[List[ValDef]]
42+
val newBodyWithStaticConstr =
43+
if (staticFields.nonEmpty) {
44+
/* do NOT put Flags.JavaStatic here. It breaks .enclosingClass */
45+
val staticCostructor = ctx.newSymbol(orig.symbol, Names.STATIC_CONSTRUCTOR, Flags.Synthetic | Flags.Method | Flags.Private, MethodType(Nil, defn.UnitType))
46+
staticCostructor.addAnnotation(Annotation(defn.ScalaStaticAnnot))
47+
staticCostructor.entered
48+
49+
val staticAssigns = staticFields.map(x => Assign(ref(x.symbol), x.rhs.changeOwner(x.symbol, staticCostructor)))
50+
tpd.DefDef(staticCostructor, Block(staticAssigns, tpd.unitLiteral)) :: newBody
51+
} else newBody
52+
53+
val oldTemplate = orig.rhs.asInstanceOf[Template]
54+
cpy.TypeDef(orig)(rhs = cpy.Template(orig.rhs)(oldTemplate.constr, oldTemplate.parents, oldTemplate.self, newBodyWithStaticConstr))
55+
}
56+
57+
def move(module: TypeDef, companion: TypeDef): List[Tree] = {
58+
if (!module.symbol.is(Flags.Module)) move(companion, module)
59+
else {
60+
val allMembers =
61+
(if(companion ne null) {companion.rhs.asInstanceOf[Template].body} else Nil) ++
62+
module.rhs.asInstanceOf[Template].body
63+
val (newModuleBody, newCompanionBody) = allMembers.partition(x => {assert(x.symbol.exists); x.symbol.owner == module.symbol})
64+
Trees.flatten(rebuild(companion, newCompanionBody) :: rebuild(module, newModuleBody) :: Nil)
65+
}
66+
}
67+
val newPairs =
68+
for ((name, classes) <- pairs)
69+
yield
70+
if (classes.tail.isEmpty)
71+
if (classes.head.symbol.is(Flags.Module)) move(classes.head, null)
72+
else List(rebuild(classes.head, classes.head.rhs.asInstanceOf[Template].body))
73+
else move(classes.head, classes.tail.head)
74+
Trees.flatten(newPairs.toList.flatten ++ others)
75+
} else trees
76+
}
77+
}

src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ import collection.mutable
2626
import ProtoTypes._
2727
import config.Printers
2828
import java.lang.AssertionError
29+
30+
import dotty.tools.dotc.core.Names
31+
2932
import scala.util.control.NonFatal
3033

3134
/** Run by -Ycheck option after a given phase, this class retypes all syntax trees
@@ -382,7 +385,7 @@ class TreeChecker extends Phase with SymTransformer {
382385
override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(implicit ctx: Context) =
383386
withDefinedSyms(ddef.tparams) {
384387
withDefinedSymss(ddef.vparamss) {
385-
if (!sym.isClassConstructor) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm")
388+
if (!sym.isClassConstructor && !(sym.name eq Names.STATIC_CONSTRUCTOR)) assert(isValidJVMMethodName(sym.name), s"${sym.fullName} name is invalid on jvm")
386389
val tpdTree = super.typedDefDef(ddef, sym)
387390
assert(isMethodType(sym.info), i"wrong type, expect a method type for ${sym.fullName}, but found: ${sym.info}")
388391
tpdTree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
485485
def canAssign(sym: Symbol) = // allow assignments from the primary constructor to class fields
486486
sym.is(Mutable, butNot = Accessor) ||
487487
ctx.owner.isPrimaryConstructor && !sym.is(Method) && sym.owner == ctx.owner.owner ||
488-
ctx.owner.name.isTraitSetterName
488+
ctx.owner.name.isTraitSetterName || ctx.owner.isStaticConstructor
489489
lhsCore.tpe match {
490490
case ref: TermRef if canAssign(ref.symbol) =>
491491
assignType(cpy.Assign(tree)(lhs1, typed(tree.rhs, ref.info)))

0 commit comments

Comments
 (0)