diff options
Diffstat (limited to 'src')
4 files changed, 83 insertions, 26 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index d519948a11..81a465ef2f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -539,8 +539,43 @@ trait ContextErrors { def NamedAndDefaultArgumentsNotSupportedForMacros(tree: Tree, fun: Tree) = NormalTypeError(tree, "macro applications do not support named and/or default arguments") - def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) = - NormalTypeError(tree, "too many arguments for "+treeSymTypeMsg(fun)) + def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree, formals: List[Type], args: List[Tree], namelessArgs: List[Tree], argPos: Array[Int]) = { + val expected = formals.size + val supplied = args.size + // pick a caret. For f(k=1,i=2,j=3), argPos[0,-1,1] b/c `k=1` taken as arg0 + val excessive = { + val i = argPos.indexWhere(_ >= expected) + if (i < 0) tree else args(i min (supplied - 1)) + } + val msg = { + val badappl = { + val excess = supplied - expected + val target = treeSymTypeMsg(fun) + + if (expected == 0) s"no arguments allowed for nullary $target" + else if (excess < 3 && expected <= 5) s"too many arguments ($supplied) for $target" + else if (expected > 10) s"$supplied arguments but expected $expected for $target" + else { + val more = + if (excess == 1) "one more argument" + else if (excess > 0) s"$excess more arguments" + else "too many arguments" + s"$more than can be applied to $target" + } + } + val unknowns = (namelessArgs zip args) collect { + case (_: Assign, AssignOrNamedArg(Ident(name), _)) => name + } + val suppl = + unknowns.size match { + case 0 => "" + case 1 => s"\nNote that '${unknowns.head}' is not a parameter name of the invoked method." + case _ => unknowns.mkString("\nNote that '", "', '", "' are not parameter names of the invoked method.") + } + s"${badappl}${suppl}" + } + NormalTypeError(excessive, msg) + } // can it still happen? see test case neg/overloaded-unapply.scala def OverloadedUnapplyError(tree: Tree) = @@ -552,7 +587,7 @@ trait ContextErrors { def MultipleVarargError(tree: Tree) = NormalTypeError(tree, "when using named arguments, the vararg parameter has to be specified exactly once") - def ModuleUsingCompanionClassDefaultArgsErrror(tree: Tree) = + def ModuleUsingCompanionClassDefaultArgsError(tree: Tree) = NormalTypeError(tree, "module extending its companion class cannot use default constructor arguments") def NotEnoughArgsError(tree: Tree, fun: Tree, missing: List[Symbol]) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 72da4498c7..9fa3564b2b 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3337,7 +3337,10 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper // #2064 duplErrorTree(WrongNumberOfArgsError(tree, fun)) } else if (lencmp > 0) { - tryTupleApply orElse duplErrorTree(TooManyArgsNamesDefaultsError(tree, fun)) + tryTupleApply orElse duplErrorTree { + val (namelessArgs, argPos) = removeNames(Typer.this)(args, params) + TooManyArgsNamesDefaultsError(tree, fun, formals, args, namelessArgs, argPos) + } } else if (lencmp == 0) { // we don't need defaults. names were used, so this application is transformed // into a block (@see transformNamedApplication in NamesDefaults) @@ -3401,7 +3404,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val lencmp2 = compareLengths(allArgs, formals) if (!sameLength(allArgs, args) && callToCompanionConstr(context, funSym)) { - duplErrorTree(ModuleUsingCompanionClassDefaultArgsErrror(tree)) + duplErrorTree(ModuleUsingCompanionClassDefaultArgsError(tree)) } else if (lencmp2 > 0) { removeNames(Typer.this)(allArgs, params) // #3818 duplErrTree diff --git a/src/repl/scala/tools/nsc/interpreter/ILoop.scala b/src/repl/scala/tools/nsc/interpreter/ILoop.scala index 8f19b4860a..66a5f08e96 100644 --- a/src/repl/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/repl/scala/tools/nsc/interpreter/ILoop.scala @@ -490,11 +490,7 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) def editCommand(what: String): Result = editCommand(what, Properties.envOrNone("EDITOR")) def editCommand(what: String, editor: Option[String]): Result = { - def diagnose(code: String) = { - echo("The edited code is incomplete!\n") - val errless = intp compileSources new BatchSourceFile("<pastie>", s"object pastel {\n$code\n}") - if (errless) echo("The compiler reports no errors.") - } + def diagnose(code: String): Unit = paste.incomplete("The edited code is incomplete!\n", "<edited>", code) def edit(text: String): Result = editor match { case Some(ed) => @@ -756,21 +752,13 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) text } def interpretCode() = { - val res = intp.withLabel(label)(intp interpret code) - // if input is incomplete, let the compiler try to say why - if (res == IR.Incomplete) { - echo("The pasted code is incomplete!\n") - // Remembrance of Things Pasted in an object - val errless = intp compileSources new BatchSourceFile(label, s"object pastel {\n$code\n}") - if (errless) echo("...but compilation found no error? Good luck with that.") - } - } - def compileCode() = { - val errless = intp compileSources new BatchSourceFile(label, code) - if (!errless) echo("There were compilation errors!") + if (intp.withLabel(label)(intp interpret code) == IR.Incomplete) + paste.incomplete("The pasted code is incomplete!\n", label, code) } + def compileCode() = paste.compilePaste(label = label, code = code) + if (code.nonEmpty) { - if (raw) compileCode() else interpretCode() + if (raw || paste.isPackaged(code)) compileCode() else interpretCode() } result } @@ -778,6 +766,27 @@ class ILoop(in0: Option[BufferedReader], protected val out: JPrintWriter) private object paste extends Pasted(prompt) { def interpret(line: String) = intp interpret line def echo(message: String) = ILoop.this echo message + + val leadingElement = raw"(?s)\s*(package\s|/)".r + def isPackaged(code: String): Boolean = { + leadingElement.findPrefixMatchOf(code) + .map(m => if (m.group(1) == "/") intp.parse.packaged(code) else true) + .getOrElse(false) + } + + // if input is incomplete, wrap and compile for diagnostics. + def incomplete(message: String, label: String, code: String): Boolean = { + echo(message) + val errless = intp.compileSources(new BatchSourceFile(label, s"object pastel {\n$code\n}")) + if (errless) echo("No error found in incomplete source.") + errless + } + + def compilePaste(label: String, code: String): Boolean = { + val errless = intp.compileSources(new BatchSourceFile(label, code)) + if (!errless) echo("There were compilation errors!") + errless + } } private object invocation { diff --git a/src/repl/scala/tools/nsc/interpreter/IMain.scala b/src/repl/scala/tools/nsc/interpreter/IMain.scala index 2f20a1cd0a..44784aa953 100644 --- a/src/repl/scala/tools/nsc/interpreter/IMain.scala +++ b/src/repl/scala/tools/nsc/interpreter/IMain.scala @@ -1101,7 +1101,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends case class Incomplete(trees: List[Tree]) extends Result case class Success(trees: List[Tree]) extends Result - def apply(line: String): Result = debugging(s"""parse("$line")""") { + def apply(line: String): Result = debugging(s"""parse("$line")""") { var isIncomplete = false def parse = { reporter.reset() @@ -1110,8 +1110,18 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends else if (isIncomplete) Incomplete(trees) else Success(trees) } - currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true) {parse} - + currentRun.parsing.withIncompleteHandler((_, _) => isIncomplete = true)(parse) + } + // code has a named package + def packaged(line: String): Boolean = { + def parses = { + reporter.reset() + val tree = newUnitParser(line).parse() + !reporter.hasErrors && { + tree match { case PackageDef(Ident(id), _) => id != nme.EMPTY_PACKAGE_NAME case _ => false } + } + } + beSilentDuring(parses) } } |