diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 30 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 29 |
2 files changed, 47 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 55a409775b..5ccc22f4dd 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -349,7 +349,7 @@ trait NamesDefaults { self: Analyzer => // @LUC TODO: make faster (don't use zipWithIndex) val namelessArgs = for ((arg, index) <- (args.zipWithIndex)) yield arg match { case Assign(Ident(name), rhs) => - val pos = params.findIndexOf(p => p.name == name && !p.hasFlag(SYNTHETIC)) + val pos = params.indexWhere(p => p.name == name && !p.hasFlag(SYNTHETIC)) if (pos == -1) { if (positionalAllowed) { argPos(index) = index @@ -362,9 +362,31 @@ trait NamesDefaults { self: Analyzer => } else if (argPos contains pos) { errorTree(arg, "parameter specified twice: "+ name) } else { - positionalAllowed = false - argPos(index) = pos - rhs + // for named arguments, check wether the assignment expression would + // typecheck. if it does, report an ambiguous error. + val param = params(pos) + val paramtpe = params(pos).tpe.cloneInfo(param) + // replace type parameters by wildcard. in the below example we need to + // typecheck (x = 1) with wildcard (not T) so that it succeeds. + // def f[T](x: T) = x + // var x = 0 + // f(x = 1) << "x = 1" typechecks with expected type WildcardType + val udp = typer.context.extractUndetparams() + val subst = new SubstTypeMap(udp, udp map (_ => WildcardType)) + val res = typer.silent(_.typed(arg, subst(paramtpe))) match { + case _: TypeError => + positionalAllowed = false + argPos(index) = pos + // if `rhs' has the form `x = ...`, wrap it into a block, prevent + // treating it as named argument again. + if (isNamed(rhs)) Block(List(), rhs) + else rhs + case t: Tree => + errorTree(arg, "reference to "+ name +" is ambiguous; it is both, a parameter\n"+ + "name of the method and the name of a variable currently in scope.") + } + typer.context.undetparams = udp + res } case _ => argPos(index) = index diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 02f6d20522..89cfcb21e2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1510,12 +1510,23 @@ trait Typers { self: Analyzer => // only one overloaded method is allowed to have defaults if (meth.owner.isClass && meth.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM)))) { - val overloads = meth.owner.info.member(meth.name) - val otherHasDefault = overloads.filter(alt => { - alt != meth && alt.paramss.exists(_.exists(_.hasFlag(DEFAULTPARAM))) - }) != NoSymbol - if (otherHasDefault) - error(meth.pos, "multiple overloaded alternatives of "+ meth +" define default arguments") + // 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(_.exists(_.tpe.typeSymbol == RepeatedParamClass))) error(meth.pos, "methods with `*'-parameters are not allowed to have default arguments") @@ -2018,8 +2029,10 @@ trait Typers { self: Analyzer => if (allArgs.length == formals.length) { // a default for each missing argument was found val (namelessArgs, argPos) = removeNames(Typer.this)(allArgs, params) - transformNamedApplication(Typer.this, mode, pt)( - treeCopy.Apply(tree, fun1, namelessArgs), argPos) + if (namelessArgs exists (_.isErroneous)) setError(tree) + else + transformNamedApplication(Typer.this, mode, pt)( + treeCopy.Apply(tree, fun1, namelessArgs), argPos) } else { tryTupleApply.getOrElse { val suffix = |