diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 6 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 3 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 4 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg.check | 6 | ||||
-rw-r--r-- | test/files/neg/t2488.check | 31 | ||||
-rw-r--r-- | test/files/neg/t2488.scala | 12 | ||||
-rw-r--r-- | test/files/neg/t5044.check | 9 | ||||
-rw-r--r-- | test/files/neg/t5044.scala | 9 | ||||
-rw-r--r-- | test/files/neg/t5801.check | 22 | ||||
-rw-r--r-- | test/files/neg/t5801.scala | 16 | ||||
-rw-r--r-- | test/files/run/t2488.check | 4 | ||||
-rw-r--r-- | test/files/run/t2488.scala | 11 |
13 files changed, 139 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index df0258832c..cb01faf619 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -1034,6 +1034,12 @@ trait ContextErrors { setError(arg) } else arg } + + def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = { + val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+ + "in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"." + context.warning(arg.pos, note) + } def UnknownParameterNameNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = { issueNormalTypeError(arg, "unknown parameter name: " + name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index 5534cd179c..1c1adee343 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -617,7 +617,8 @@ trait Infer { } else if (argPos.contains(pos)) { // parameter specified twice namesOK = false } else { - positionalAllowed = false + if (index != pos) + positionalAllowed = false argPos(index) = pos } index += 1 diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 9e6b9617a5..88e464a1f4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -478,7 +478,14 @@ trait NamesDefaults { self: Analyzer => // instead of arg, but can't do that because eventually setType(ErrorType) // is called, and EmptyTree can only be typed NoType. Thus we need to // disable conforms as a view... - try typer.silent(_.typed(arg, subst(paramtpe))) match { + val errsBefore = reporter.ERROR.count + try typer.silent { tpr => + val res = tpr.typed(arg, subst(paramtpe)) + // better warning for SI-5044: if `silent` was not actually silent give a hint to the user + if (errsBefore < reporter.ERROR.count) + WarnAfterNonSilentRecursiveInference(param, arg)(context) + res + } match { case SilentResultValue(t) => !t.isErroneous // #4041 case _ => false } @@ -487,7 +494,7 @@ trait NamesDefaults { self: Analyzer => // CyclicReferences. Fix for #3685 case cr @ CyclicReference(sym, _) => (sym.name == param.name) && sym.accessedOrSelf.isVariable && { - NameClashError(sym, arg)(typer.context) + NameClashError(sym, arg)(context) true } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7419ec3bce..e40a567f1d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -114,6 +114,8 @@ trait Typers extends Modes with Adaptations with Taggings { case MethodType(params, _) => val argResultsBuff = new ListBuffer[SearchResult]() val argBuff = new ListBuffer[Tree]() + // paramFailed cannot be initialized with params.exists(_.tpe.isError) because that would + // hide some valid errors for params preceding the erroneous one. var paramFailed = false def mkPositionalArg(argTree: Tree, paramName: Name) = argTree @@ -129,7 +131,7 @@ trait Typers extends Modes with Adaptations with Taggings { for(ar <- argResultsBuff) paramTp = paramTp.subst(ar.subst.from, ar.subst.to) - val res = if (paramFailed) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) + val res = if (paramFailed || (paramTp.isError && {paramFailed = true; true})) SearchFailure else inferImplicit(fun, paramTp, context.reportErrors, false, context) argResultsBuff += res if (res != SearchFailure) { diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index b5f544c97e..2809350855 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -149,8 +149,12 @@ names-defaults-neg.scala:170: error: reference to x is ambiguous; it is both a m names-defaults-neg.scala:177: error: variable definition needs type because 'x' is used as a named argument in its body. class u15 { var x = u.f(x = 1) } ^ +names-defaults-neg.scala:177: warning: type-checking the invocation of method f checks if the named argument expression 'x = ...' is a valid assignment +in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for x. + class u15 { var x = u.f(x = 1) } + ^ names-defaults-neg.scala:180: error: reference to x is ambiguous; it is both a method parameter and a variable in scope. class u18 { var x: Int = u.f(x = 1) } ^ -one warning found +two warnings found 41 errors found diff --git a/test/files/neg/t2488.check b/test/files/neg/t2488.check new file mode 100644 index 0000000000..170dbf88ff --- /dev/null +++ b/test/files/neg/t2488.check @@ -0,0 +1,31 @@ +t2488.scala:7: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (b: Int, Int) + println(c.f(b = 2, 2)) + ^ +t2488.scala:8: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (a: Int, c: Int) + println(c.f(a = 2, c = 2)) + ^ +t2488.scala:9: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (Int, c: Int) + println(c.f(2, c = 2)) + ^ +t2488.scala:10: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (c: Int, Int) + println(c.f(c = 2, 2)) + ^ +t2488.scala:11: error: overloaded method value f with alternatives: + ()Int <and> + (a: Int,b: Int)Int + cannot be applied to (Int) + println(c.f(2)) + ^ +5 errors found diff --git a/test/files/neg/t2488.scala b/test/files/neg/t2488.scala new file mode 100644 index 0000000000..8db052eec1 --- /dev/null +++ b/test/files/neg/t2488.scala @@ -0,0 +1,12 @@ +class C { + def f(a:Int, b:Int) = 1 + def f() = 2 +} +object Test extends App { + val c = new C() + println(c.f(b = 2, 2)) + println(c.f(a = 2, c = 2)) + println(c.f(2, c = 2)) + println(c.f(c = 2, 2)) + println(c.f(2)) +} diff --git a/test/files/neg/t5044.check b/test/files/neg/t5044.check new file mode 100644 index 0000000000..197da2a4e8 --- /dev/null +++ b/test/files/neg/t5044.check @@ -0,0 +1,9 @@ +t5044.scala:7: error: recursive value a needs type + val id = m(a) + ^ +t5044.scala:6: warning: type-checking the invocation of method foo checks if the named argument expression 'id = ...' is a valid assignment +in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for id. + val a = foo(id = 1) + ^ +one warning found +one error found diff --git a/test/files/neg/t5044.scala b/test/files/neg/t5044.scala new file mode 100644 index 0000000000..2663ec1bbb --- /dev/null +++ b/test/files/neg/t5044.scala @@ -0,0 +1,9 @@ +class T { + def foo[T](id: T) = 0 + def m(a: Int) = 0 + + def f { + val a = foo(id = 1) + val id = m(a) + } +} diff --git a/test/files/neg/t5801.check b/test/files/neg/t5801.check new file mode 100644 index 0000000000..abf8e6e932 --- /dev/null +++ b/test/files/neg/t5801.check @@ -0,0 +1,22 @@ +t5801.scala:1: error: object sth is not a member of package scala +import scala.sth + ^ +t5801.scala:4: error: not found: value sth + def foo(a: Int)(implicit b: sth.Sth): Unit = {} + ^ +t5801.scala:7: error: not found: value sth + def bar(x: Int)(implicit y: Int): sth.Sth = null + ^ +t5801.scala:8: error: could not find implicit value for parameter y: Int + bar(1) + ^ +t5801.scala:10: error: not found: value sth + def meh(x: Int)(implicit a: sth.Sth, b: Int): Unit = {} + ^ +t5801.scala:13: error: not found: value sth + def meh2(x: Int)(implicit b: Int, a: sth.Sth): Unit = {} + ^ +t5801.scala:14: error: could not find implicit value for parameter b: Int + meh2(1) + ^ +7 errors found diff --git a/test/files/neg/t5801.scala b/test/files/neg/t5801.scala new file mode 100644 index 0000000000..d452222ac8 --- /dev/null +++ b/test/files/neg/t5801.scala @@ -0,0 +1,16 @@ +import scala.sth + +object Test extends App { + def foo(a: Int)(implicit b: sth.Sth): Unit = {} + foo(1) + + def bar(x: Int)(implicit y: Int): sth.Sth = null + bar(1) + + def meh(x: Int)(implicit a: sth.Sth, b: Int): Unit = {} + meh(1) + + def meh2(x: Int)(implicit b: Int, a: sth.Sth): Unit = {} + meh2(1) +} + diff --git a/test/files/run/t2488.check b/test/files/run/t2488.check new file mode 100644 index 0000000000..1af4bf8965 --- /dev/null +++ b/test/files/run/t2488.check @@ -0,0 +1,4 @@ +1 +1 +1 +2 diff --git a/test/files/run/t2488.scala b/test/files/run/t2488.scala new file mode 100644 index 0000000000..22abdf8af2 --- /dev/null +++ b/test/files/run/t2488.scala @@ -0,0 +1,11 @@ +class C { + def f(a:Int, b:Int) = 1 + def f() = 2 +} +object Test extends App { + val c = new C() + println(c.f(a = 1,2)) + println(c.f(a = 1, b = 2)) + println(c.f(b = 2, a = 1)) + println(c.f()) +} |