diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala | 27 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg.check | 28 | ||||
-rw-r--r-- | test/files/neg/names-defaults-neg.scala | 47 |
3 files changed, 95 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index d783cf9c9f..fcafbc3b4c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -444,7 +444,20 @@ trait NamesDefaults { self: Analyzer => } val reportAmbiguousErrors = typer.context.reportAmbiguousErrors typer.context.reportAmbiguousErrors = false - val res = typer.silent(_.typed(arg, subst(paramtpe))) match { + + val typedAssign = try { + typer.silent(_.typed(arg, subst(paramtpe))) + } catch { + // `silent` only catches and returns TypeErrors which are not CyclicReferences + // fix for #3685 + case cr @ CyclicReference(sym, info) if (sym.name == param.name) => + if (sym.isVariable || sym.isGetter && sym.accessed.isVariable) { + // named arg not allowed + typer.context.error(sym.pos, "variable definition needs type because the name is used as named argument the definition.") + typer.infer.setError(arg) + } else cr // named arg OK + } + val res = typedAssign match { case _: TypeError => // if the named argument is on the original parameter // position, positional after named is allowed. @@ -453,13 +466,15 @@ trait NamesDefaults { self: Analyzer => argPos(index) = pos rhs case t: Tree => - // this throws an exception that's caught in `tryTypedApply` (as it uses `silent`) - // unfortunately, tryTypedApply recovers from the exception if you use errorTree(arg, ...) and conforms is allowed as a view (see tryImplicit in Implicits) - // because it tries to produce a new qualifier (if the old one was P, the new one will be conforms.apply(P)), and if that works, it pretends nothing happened - // so, to make sure tryTypedApply fails, would like to pass EmptyTree instead of arg, but can't do that because eventually setType(ErrorType) is called, and EmptyTree only accepts NoType as its tpe - // thus, we need to disable conforms as a view... + if (!t.isErroneous) { + // this throws an exception that's caught in `tryTypedApply` (as it uses `silent`) + // unfortunately, tryTypedApply recovers from the exception if you use errorTree(arg, ...) and conforms is allowed as a view (see tryImplicit in Implicits) + // because it tries to produce a new qualifier (if the old one was P, the new one will be conforms.apply(P)), and if that works, it pretends nothing happened + // so, to make sure tryTypedApply fails, would like to pass EmptyTree instead of arg, but can't do that because eventually setType(ErrorType) is called, and EmptyTree only accepts NoType as its tpe + // thus, we need to disable conforms as a view... 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.") + } else t // error was reported above } typer.context.reportAmbiguousErrors = reportAmbiguousErrors //@M note that we don't get here when an ambiguity was detected (during the computation of res), diff --git a/test/files/neg/names-defaults-neg.check b/test/files/neg/names-defaults-neg.check index ec786c5e03..1f77b828b7 100644 --- a/test/files/neg/names-defaults-neg.check +++ b/test/files/neg/names-defaults-neg.check @@ -132,5 +132,31 @@ names-defaults-neg.scala:131: error: parameter specified twice: a names-defaults-neg.scala:132: error: wrong number of parameters; expected = 2 val taf4: (Int, String) => Unit = testAnnFun(_, b = _) ^ +names-defaults-neg.scala:140: error: variable definition needs type because the name is used as named argument the definition. + def t3 { var x = t.f(x = 1) } + ^ +names-defaults-neg.scala:143: error: variable definition needs type because the name is used as named argument the definition. + object t6 { var x = t.f(x = 1) } + ^ +names-defaults-neg.scala:146: error: variable definition needs type because the name is used as named argument the definition. + class t9 { var x = t.f(x = 1) } + ^ +names-defaults-neg.scala:160: error: variable definition needs type because the name is used as named argument the definition. + def u3 { var x = u.f(x = 1) } + ^ +names-defaults-neg.scala:163: error: variable definition needs type because the name is used as named argument the definition. + def u6 { var x = u.f(x = "32") } + ^ +names-defaults-neg.scala:166: error: reference to x is ambiguous; it is both, a parameter +name of the method and the name of a variable currently in scope. + def u9 { var x: Int = u.f(x = 1) } + ^ +names-defaults-neg.scala:173: error: variable definition needs type because the name is used as named argument the definition. + class u15 { var x = u.f(x = 1) } + ^ +names-defaults-neg.scala:176: error: reference to x is ambiguous; it is both, a parameter +name of the method and the name of a variable currently in scope. + class u18 { var x: Int = u.f(x = 1) } + ^ one warning found -32 errors found +40 errors found diff --git a/test/files/neg/names-defaults-neg.scala b/test/files/neg/names-defaults-neg.scala index 8d1ec4ce96..4350f9860d 100644 --- a/test/files/neg/names-defaults-neg.scala +++ b/test/files/neg/names-defaults-neg.scala @@ -131,3 +131,50 @@ object anfun { val taf3 = testAnnFun(b = _: String, a = get(8)) val taf4: (Int, String) => Unit = testAnnFun(_, b = _) } + +object t3685 { + object t { def f(x: Int) = x } + + def t1 { def x = t.f(x = 1) } + def t2 { val x = t.f(x = 1) } + def t3 { var x = t.f(x = 1) } + object t4 { def x = t.f(x = 1) } + object t5 { val x = t.f(x = 1) } + object t6 { var x = t.f(x = 1) } + class t7 { def x = t.f(x = 1) } + class t8 { val x = t.f(x = 1) } + class t9 { var x = t.f(x = 1) } + + def t10 { def x: Int = t.f(x = 1) } + def t11 { val x: Int = t.f(x = 1) } + def t12 { var x: Int = t.f(x = 1) } + class t13 { def x: Int = t.f(x = 1) } + class t14 { val x: Int = t.f(x = 1) } + class t15 { var x: Int = t.f(x = 1) } + + + object u { def f[T](x: T) = 100 } + + def u1 { def x = u.f(x = 1) } + def u2 { val x = u.f(x = 1) } + def u3 { var x = u.f(x = 1) } + def u4 { def x = u.f(x = "23") } + def u5 { val x = u.f(x = "32") } + def u6 { var x = u.f(x = "32") } + def u7 { def x: Int = u.f(x = 1) } + def u8 { val x: Int = u.f(x = 1) } + def u9 { var x: Int = u.f(x = 1) } + def u10 { def x: Int = u.f(x = "32") } + def u11 { val x: Int = u.f(x = "32") } + def u12 { var x: Int = u.f(x = "32") } + + class u13 { def x = u.f(x = 1) } + class u14 { val x = u.f(x = 1) } + class u15 { var x = u.f(x = 1) } + class u16 { def x: Int = u.f(x = 1) } + class u17 { val x: Int = u.f(x = 1) } + class u18 { var x: Int = u.f(x = 1) } + class u19 { def x: Int = u.f(x = "32") } + class u20 { val x: Int = u.f(x = "32") } + class u21 { var x: Int = u.f(x = "32") } +} |