Skip to content

Fix #3171: Fix handling default getters in secondary constructors #3201

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 1 commit into from
Sep 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 18 additions & 8 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ object desugar {
* def f$default$1[T] = 1
* def f$default$2[T](x: Int) = x + "m"
*/
def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
private def defDef(meth: DefDef, isPrimaryConstructor: Boolean = false)(implicit ctx: Context): Tree = {
val DefDef(name, tparams, vparamss, tpt, rhs) = meth
val mods = meth.mods
val epbuf = new ListBuffer[ValDef]
Expand Down Expand Up @@ -254,11 +254,17 @@ object desugar {
.withFlags((mods.flags & AccessFlags).toCommonFlags)
.withMods(Nil)

val (constr1, defaultGetters) = defDef(constr0, isPrimaryConstructor = true) match {
case meth: DefDef => (meth, Nil)
case Thicket((meth: DefDef) :: defaults) => (meth, defaults)
var defaultGetters: List[Tree] = Nil

def decompose(ddef: Tree): DefDef = ddef match {
case meth: DefDef => meth
case Thicket((meth: DefDef) :: defaults) =>
defaultGetters = defaults
meth
}

val constr1 = decompose(defDef(constr0, isPrimaryConstructor = true))

// The original type and value parameters in the constructor already have the flags
// needed to be type members (i.e. param, and possibly also private and local unless
// prefixed by type or val). `tparams` and `vparamss` are the type parameters that
Expand Down Expand Up @@ -299,9 +305,11 @@ object desugar {
// to auxiliary constructors
val normalizedBody = impl.body map {
case ddef: DefDef if ddef.name.isConstructorName =>
addEvidenceParams(
cpy.DefDef(ddef)(tparams = constrTparams),
evidenceParams(constr1).map(toDefParam))
decompose(
defDef(
addEvidenceParams(
cpy.DefDef(ddef)(tparams = constrTparams),
evidenceParams(constr1).map(toDefParam))))
case stat =>
stat
}
Expand Down Expand Up @@ -680,7 +688,9 @@ object desugar {
def defTree(tree: Tree)(implicit ctx: Context): Tree = tree match {
case tree: ValDef => valDef(tree)
case tree: TypeDef => if (tree.isClassDef) classDef(tree) else tree
case tree: DefDef => defDef(tree)
case tree: DefDef =>
if (tree.name.isConstructorName) tree // was already handled by enclosing classDef
else defDef(tree)
case tree: ModuleDef => moduleDef(tree)
case tree: PatDef => patDef(tree)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ trait Checking {
else doubleDefError(decl, other)
}
if ((decl is HasDefaultParams) && (other is HasDefaultParams)) {
ctx.error(em"two or more overloaded variants of $decl have default arguments")
ctx.error(em"two or more overloaded variants of $decl have default arguments", decl.pos)
decl resetFlag HasDefaultParams
}
}
Expand Down
10 changes: 10 additions & 0 deletions tests/neg/i3171.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
object Test {
class C(x: Int = 1, y: Int) {
def this(x: Int = 1)(y: String) = // error: two or more overloaded methods have default getters
this(x, y.toInt)
}

def test: Unit = {
new C()("1") // error: missing argument
}
}
10 changes: 10 additions & 0 deletions tests/pos/i3171.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
object Test {
class C(x: Int, y: Int) {
def this(x: Int = 1)(y: String) =
this(x, y.toInt)
}

def test: Unit = {
new C()("1")
}
}