Skip to content

Commit 772d741

Browse files
committed
Fix scala#3171: Fix handling default getters in secondary constructors
Previous logic would place them in the enclosing class instead of in the companion object where they belong. Also, define position for error that checks against multiple overloaded alternatives with default arguments.
1 parent 60d14c3 commit 772d741

File tree

4 files changed

+40
-9
lines changed

4 files changed

+40
-9
lines changed

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

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ object desugar {
149149
* def f$default$1[T] = 1
150150
* def f$default$2[T](x: Int) = x + "m"
151151
*/
152-
def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
152+
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
153153
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
154154
val mods = meth.mods
155155
val epbuf = new ListBuffer[ValDef]
@@ -254,11 +254,17 @@ object desugar {
254254
.withFlags((mods.flags & AccessFlags).toCommonFlags)
255255
.withMods(Nil)
256256

257-
val (constr1, defaultGetters) = defDef(constr0, isPrimaryConstructor = true) match {
258-
case meth: DefDef => (meth, Nil)
259-
case Thicket((meth: DefDef) :: defaults) => (meth, defaults)
257+
var defaultGetters: List[Tree] = Nil
258+
259+
def decompose(ddef: Tree): DefDef = ddef match {
260+
case meth: DefDef => meth
261+
case Thicket((meth: DefDef) :: defaults) =>
262+
defaultGetters = defaults
263+
meth
260264
}
261265

266+
val constr1 = decompose(defDef(constr0, isPrimaryConstructor = true))
267+
262268
// The original type and value parameters in the constructor already have the flags
263269
// needed to be type members (i.e. param, and possibly also private and local unless
264270
// prefixed by type or val). `tparams` and `vparamss` are the type parameters that
@@ -299,9 +305,11 @@ object desugar {
299305
// to auxiliary constructors
300306
val normalizedBody = impl.body map {
301307
case ddef: DefDef if ddef.name.isConstructorName =>
302-
addEvidenceParams(
303-
cpy.DefDef(ddef)(tparams = constrTparams),
304-
evidenceParams(constr1).map(toDefParam))
308+
decompose(
309+
defDef(
310+
addEvidenceParams(
311+
cpy.DefDef(ddef)(tparams = constrTparams),
312+
evidenceParams(constr1).map(toDefParam))))
305313
case stat =>
306314
stat
307315
}
@@ -680,7 +688,10 @@ object desugar {
680688
def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
681689
case tree: ValDef => valDef(tree)
682690
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree
683-
case tree: DefDef => defDef(tree)
691+
case tree: DefDef =>
692+
693+
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
694+
else defDef(tree)
684695
case tree: ModuleDef => moduleDef(tree)
685696
case tree: PatDef => patDef(tree)
686697
}

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ trait Checking {
625625
else doubleDefError(decl, other)
626626
}
627627
if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
628-
ctx.error(em"two or more overloaded variants of $decl have default arguments")
628+
ctx.error(em"two or more overloaded variants of $decl have default arguments", decl.pos)
629629
decl resetFlag HasDefaultParams
630630
}
631631
}

tests/neg/i3171.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object Test {
2+
class C(x: Int = 1, y: Int) {
3+
def this(x: Int = 1)(y: String) = // error: two or more overloaded methods have default getters
4+
this(x, y.toInt)
5+
}
6+
7+
def test: Unit = {
8+
new C()("1") // error: missing argument
9+
}
10+
}

tests/pos/i3171.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object Test {
2+
class C(x: Int, y: Int) {
3+
def this(x: Int = 1)(y: String) =
4+
this(x, y.toInt)
5+
}
6+
7+
def test: Unit = {
8+
new C()("1")
9+
}
10+
}

0 commit comments

Comments
 (0)