From 0ef0cf937128fe3aa050be9d2a693537b0f72e49 Mon Sep 17 00:00:00 2001 From: rytz Date: Thu, 24 Sep 2009 12:45:00 +0000 Subject: [PATCH] fixed #2290 and #2325 git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@18772 5e8d7ff9-d8ef-0310-90f0-a4852d11357a --- .../tools/nsc/typechecker/NamesDefaults.scala | 4 ++- .../tools/nsc/typechecker/RefChecks.scala | 27 +++++++++++++++- .../scala/tools/nsc/typechecker/Typers.scala | 31 ++++--------------- src/library/scala/concurrent/ops.scala | 19 ++---------- test/files/neg/names-defaults-neg-ref.check | 16 ++++++++++ test/files/neg/names-defaults-neg-ref.scala | 26 ++++++++++++++++ test/files/neg/names-defaults-neg.check | 11 +------ test/files/neg/names-defaults-neg.scala | 6 ---- test/files/run/names-defaults.scala | 7 +++++ 9 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 test/files/neg/names-defaults-neg-ref.check create mode 100644 test/files/neg/names-defaults-neg-ref.scala diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index fb7734f1d..0e11cb536 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -233,7 +233,9 @@ trait NamesDefaults { self: Analyzer => }) List.map2(symPs, args)((symP, arg) => { val (sym, byName) = symP - val body = if (byName) blockTyper.typed(Function(List(), arg)) + // resetAttrs required for #2290. given a block { val x = 1; x }, when wrapping into a function + // () => { val x = 1; x }, the owner of symbol x must change (to the apply method of the function). + val body = if (byName) blockTyper.typed(Function(List(), resetAttrs(arg))) else arg atPos(body.pos)(ValDef(sym, body).setType(NoType)) }) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index cbdacc102..c139f4015 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -65,6 +65,30 @@ abstract class RefChecks extends InfoTransform { var currentApplication: Tree = EmptyTree var inPattern: Boolean = false + // only one overloaded alternative is allowed to define default arguments + private def checkDefaultsInOverloaded(clazz: Symbol) { + def check(members: List[Symbol]): Unit = members match { + case x :: xs => + if (x.paramss.exists(_.exists(p => p.hasFlag(DEFAULTPARAM)))) { + val others = xs.filter(alt => { + alt.name == x.name && + alt.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM))) && + (!alt.isConstructor || alt.owner == x.owner) // constructors of different classes are allowed to have defaults + }) + if (!others.isEmpty) { + val all = x :: others + val rest = if (all.exists(_.owner != clazz)) ".\nThe members with defaults are defined in "+ + all.map(_.owner).mkString("", " and ", ".") + unit.error(clazz.pos, "in "+ clazz +", multiple overloaded alternatives of "+ x + + " define default arguments"+ rest) + } + } + check(xs) + case _ => () + } + check(clazz.info.members) + } + // Override checking ------------------------------------------------------------ /** 1. Check all members of class `clazz' for overriding conditions. @@ -891,8 +915,9 @@ abstract class RefChecks extends InfoTransform { case Template(_, _, _) => localTyper = localTyper.atOwner(tree, currentOwner) validateBaseTypes(currentOwner) + checkDefaultsInOverloaded(currentOwner) checkAllOverrides(currentOwner) - + case TypeTree() => val existentialParams = new ListBuffer[Symbol] doTypeTraversal { // check all bounds, except those that are diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 9e214182c..5b5734b2e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1550,30 +1550,9 @@ trait Typers { self: Analyzer => for (vparams <- ddef.vparamss; vparam <- vparams) checkStructuralCondition(meth.owner, vparam) - // only one overloaded method is allowed to have defaults - if (phase.id <= currentRun.typerPhase.id && - meth.owner.isClass && meth.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM)))) { - // don't do the check if it has already failed for another alternatvie - if (meth.paramss.exists(_.exists(p => p.hasFlag(DEFAULTPARAM) && - !p.defaultGetter.tpe.isError))) { - val overloads = meth.owner.info.member(meth.name) - val others = overloads.filter(alt => { - alt != meth && alt.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM))) - }) - if (others != NoSymbol) { - // setting `ErrorType' to defaultGetters prevents the error - // messages saying "foo$default$1 is defined twice" - for (ps <- meth.paramss; p <- ps) - if (p hasFlag DEFAULTPARAM) p.defaultGetter.setInfo(ErrorType) - for (alt <- others.alternatives; ps <- alt.paramss; p <- ps) - if (p hasFlag DEFAULTPARAM) p.defaultGetter.setInfo(ErrorType) - error(meth.pos, "multiple overloaded alternatives of "+ meth +" define default arguments") - } - } - - if (meth.paramss.exists(ps => ps.exists(_.hasFlag(DEFAULTPARAM)) && isRepeatedParamType(ps.last.tpe))) - error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments") - } + if (phase.id <= currentRun.typerPhase.id && meth.owner.isClass && + meth.paramss.exists(ps => ps.exists(_.hasFlag(DEFAULTPARAM)) && isRepeatedParamType(ps.last.tpe))) + error(meth.pos, "a parameter section with a `*'-parameter is not allowed to have default arguments") treeCopy.DefDef(ddef, typedMods, ddef.name, tparams1, vparamss1, tpt1, rhs1) setType NoType } @@ -1835,7 +1814,9 @@ trait Typers { self: Analyzer => while ((e1 ne null) && e1.owner == scope) { if (!accesses(e.sym, e1.sym) && !accesses(e1.sym, e.sym) && (e.sym.isType || inBlock || (e.sym.tpe matches e1.sym.tpe))) - if (!e.sym.isErroneous && !e1.sym.isErroneous) + // default getters are defined twice when multiple overloads have defaults. an + // error for this is issued in RefChecks.checkDefaultsInOverloaded + if (!e.sym.isErroneous && !e1.sym.isErroneous && !e.sym.hasFlag(DEFAULTPARAM)) error(e.sym.pos, e1.sym+" is defined twice"+ {if(!settings.debug.value) "" else " in "+unit.toString}) e1 = scope.lookupNextEntry(e1); diff --git a/src/library/scala/concurrent/ops.scala b/src/library/scala/concurrent/ops.scala index 48bb2d849..bc72bbe04 100644 --- a/src/library/scala/concurrent/ops.scala +++ b/src/library/scala/concurrent/ops.scala @@ -20,12 +20,7 @@ import scala.util.control.Exception.allCatch */ object ops { - // !!! I don't think this should be implicit, but it does need to be - // made available as a default argument (difficult at present, see spawn.) - // If it is merely implicit without being specified as a default, then it - // will not be in scope for callers unless ops._ is first imported. - implicit val defaultRunner: FutureTaskRunner = - TaskRunners.threadRunner + val defaultRunner: FutureTaskRunner = TaskRunners.threadRunner /** * If expression computed successfully return it in Right, @@ -49,12 +44,7 @@ object ops * * @param p the expression to evaluate */ - // !!! this should have a signature like: - // def spawn(p: => Unit)(implicit runner: TaskRunner = defaultRunner): Unit - // but at present the mixture of by-name argument and default implicit causes a crash. - - def spawn(p: => Unit): Unit = spawn(p, defaultRunner) - def spawn(p: => Unit, runner: TaskRunner): Unit = { + def spawn(p: => Unit)(implicit runner: TaskRunner = defaultRunner): Unit = { runner execute runner.functionAsTask(() => p) } @@ -62,10 +52,7 @@ object ops * @param p ... * @return ... */ - // See spawn above, this should have a signature like - // def future[A](p: => A)(implicit runner: FutureTaskRunner = defaultRunner): () => A - def future[A](p: => A): () => A = future[A](p, defaultRunner) - def future[A](p: => A, runner: FutureTaskRunner): () => A = { + def future[A](p: => A)(implicit runner: FutureTaskRunner = defaultRunner): () => A = { runner.futureAsFunction(runner submit runner.functionAsTask(() => p)) } diff --git a/test/files/neg/names-defaults-neg-ref.check b/test/files/neg/names-defaults-neg-ref.check new file mode 100644 index 000000000..ac3781676 --- /dev/null +++ b/test/files/neg/names-defaults-neg-ref.check @@ -0,0 +1,16 @@ +names-defaults-neg-ref.scala:3: error: in anonymous class $anon, multiple overloaded alternatives of method f define default arguments. +The members with defaults are defined in trait B2235 and trait A2235. + new A2235 with B2235 + ^ +names-defaults-neg-ref.scala:7: error: in class A, multiple overloaded alternatives of method foo define default arguments() +class A { + ^ +names-defaults-neg-ref.scala:17: error: in class C, multiple overloaded alternatives of method bar define default arguments. +The members with defaults are defined in class C and class B. +class C extends B { + ^ +names-defaults-neg-ref.scala:21: error: overriding method bar$default$1 in class B of type => String; + method bar$default$1 has incompatible type + def bar(i: Int = 129083) = i + ^ +four errors found diff --git a/test/files/neg/names-defaults-neg-ref.scala b/test/files/neg/names-defaults-neg-ref.scala new file mode 100644 index 000000000..4611aadd2 --- /dev/null +++ b/test/files/neg/names-defaults-neg-ref.scala @@ -0,0 +1,26 @@ +object Test extends Application { + // #2235 + new A2235 with B2235 +} + +// only one overloaded alternative is allowed to have defaults +class A { + def foo(a: Int = 0) = a + def foo(b: String = "another") = b +} + +class B { + def foo(a: Int) = a + def bar(u: String = "ldksj") = u +} + +class C extends B { + override def foo(a: Int = 1092) = a + def foo(b: String = "lskdfj") + + def bar(i: Int = 129083) = i +} + +// #2235 +trait A2235 { def f(x: Int = 1) = x } +trait B2235 { def f(x: String = "1") = x } diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index d8eb03fba..057a0519d 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -104,13 +104,4 @@ names-defaults-neg.scala:83: error: type mismatch; Error occured in an application involving default arguments. new A2[String]() ^ -names-defaults-neg.scala:95: error: multiple overloaded alternatives of method foo define default arguments - def foo(a: Int = 0) = a - ^ -names-defaults-neg.scala:105: error: multiple overloaded alternatives of method foo define default arguments - override def foo(a: Int = 1092) = a - ^ -names-defaults-neg.scala:108: error: multiple overloaded alternatives of method bar define default arguments - def bar(i: Int = 129083) = i - ^ -28 errors found +25 errors found diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala index cf149d4b3..5829da361 100644 --- a/test/files/neg/names-defaults-neg.scala +++ b/test/files/neg/names-defaults-neg.scala @@ -90,12 +90,6 @@ object Test extends Application { def test8[T](x: => T) = println("test8") } -// only one overloaded alternative is allowed to have defaults -class A { - def foo(a: Int = 0) = a - def foo(b: String = "another") = b -} - class B { def foo(a: Int) = a def bar(u: String = "ldksj") = u diff --git a/test/files/run/names-defaults.scala b/test/files/run/names-defaults.scala index 8e8c8a1e4..05f0afa19 100644 --- a/test/files/run/names-defaults.scala +++ b/test/files/run/names-defaults.scala @@ -251,6 +251,13 @@ object Test extends Application { // (cannot call f using the default, List(1,2) doesn't match the param type) + // #2290 + def spawn(a: Int, b: => Unit) = { () } + def t { + spawn(b = { val ttt = 1; ttt }, a = 0) + } + + // DEFINITIONS def test1(a: Int, b: String) = println(a +": "+ b) def test2(u: Int, v: Int)(k: String, l: Int) = println(l +": "+ k +", "+ (u + v))