8000 Deprecate assignments in argument position by lrytz · Pull Request #6089 · scala/scala · GitHub
[go: up one dir, main page]

Skip to content

Deprecate assignments in argument position #6089

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statemen 8000 t. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1337,8 +1337,12 @@ trait ContextErrors {
context.warning(arg.pos, note)
}

def UnknownParameterNameNamesDefaultError(arg: Tree, name: Name)(implicit context: Context) = {
issueNormalTypeError(arg, "unknown parameter name: " + name)
def UnknownParameterNameNamesDefaultError(arg: Tree, name: Name, isVariableInScope: Boolean)(implicit context: Context) = {
val suffix =
if (isVariableInScope)
s"\nNote that assignments in argument position are no longer allowed since Scala 2.13.\nTo express the assignment expression, wrap it in brackets, e.g., `{ $name = ... }`."
else ""
issueNormalTypeError(arg, s"unknown parameter name: $name$suffix")
setError(arg)
}

Expand Down
18 changes: 15 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ trait NamesDefaults { self: Analyzer =>
} else NoSymbol
}

def isVariableInScope(context: Context, name: Name): Boolean = {
context.lookupSymbol(name, _.isVariable).isSuccess
}

/** A full type check is very expensive; let's make sure there's a name
* somewhere which could potentially be ambiguous before we go that route.
*/
Expand Down Expand Up @@ -593,19 +597,27 @@ trait NamesDefaults { self: Analyzer =>
def stripNamedArg(arg: AssignOrNamedArg, argIndex: Int): Tree = {
val AssignOrNamedArg(Ident(name), rhs) = arg
params indexWhere (p => matchesName(p, name, argIndex)) match {
case -1 if positionalAllowed =>
case -1 if positionalAllowed && !settings.isScala213 =>
if (isVariableInScope(context0, name)) {
// only issue the deprecation warning if `name` is in scope, this avoids the warning when mis-spelling a parameter name.
context0.deprecationWarning(
arg.pos,
context0.owner,
s"assignments in argument position are deprecated in favor of named arguments. Wrap the assignment in brackets, e.g., `{ $name = ... }`.",
"2.12.4")
}
// prevent isNamed from being true when calling doTypedApply recursively,
// treat the arg as an assignment of type Unit
Assign(arg.lhs, rhs) setPos arg.pos
case -1 =>
UnknownParameterNameNamesDefaultError(arg, name)
UnknownParameterNameNamesDefaultError(arg, name, isVariableInScope(context0, name))
case paramPos if argPos contains paramPos =>
val existingArgIndex = argPos.indexWhere(_ == paramPos)
val otherName = Some(args(paramPos)) collect {
case AssignOrNamedArg(Ident(oName), _) if oName != name => oName
}
DoubleParamNamesDefaultError(arg, name, existingArgIndex+1, otherName)
case paramPos if isAmbiguousAssignment(typer, params(paramPos), arg) =>
case paramPos if !settings.isScala213 && isAmbiguousAssignment(typer, params(paramPos), arg) =>
AmbiguousReferenceInNamesDefaultError(arg, name)
case paramPos if paramPos != argIndex =>
positionalAllowed = false // named arg is not in original parameter order: require names after this
Expand Down
21 changes: 19 additions & 2 deletions test/files/neg/checksensible.check
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
checksensible.scala:45: warning: Adaptation of argument list by inserting () is deprecated: this is unlikely to be what you want.
signature: Any.==(x$1: Any): Boolean
given arguments: <none>
after adaptation: Any.==((): Unit)
() == ()
^
checksensible.scala:48: warning: Adaptation of argument list by inserting () is deprecated: this is unlikely to be what you want.
signature: Object.!=(x$1: Any): Boolean
given arguments: <none>
after adaptation: Object.!=((): Unit)
scala.runtime.BoxedUnit.UNIT != ()
^
checksensible.scala:49: warning: Adaptation of argument list by inserting () is deprecated: this is unlikely to be what you want.
signature: Any.!=(x$1: Any): Boolean
given arguments: <none>
after adaptation: Any.!=((): Unit)
(scala.runtime.BoxedUnit.UNIT: java.io.Serializable) != () // shouldn't warn
^
checksensible.scala:13: warning: comparing a fresh object using `eq' will always yield false
(new AnyRef) eq (new AnyRef)
^
Expand Down Expand Up @@ -97,7 +115,6 @@ checksensible.scala:84: warning: comparing values of types EqEqRefTest.this.C3 a
checksensible.scala:95: warning: comparing values of types Unit and Int using `!=' will always yield true
while ((c = in.read) != -1)
^
warning: there were three deprecation warnings (since 2.11.0); re-run with -deprecation for details
error: No warnings can be incurred under -Xfatal-warnings.
34 warnings found
36 warnings found
one error found
2 changes: 1 addition & 1 deletion test/files/neg/checksensible.flags
Original file line number Diff line number Diff line change
@@ -1 +1 @@
-Xfatal-warnings
-Xfatal-warnings -deprecation
16 changes: 16 additions & 0 deletions test/files/neg/names-defaults-neg-213.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
names-defaults-neg-213.scala:7: warning: a pure expression does nothing in statement position
f1(x = 1) // named arg in 2.13 (value discard), not ambiguous
^
names-defaults-neg-213.scala:8: error: unknown parameter name: x
Note that assignments in argument position are no longer allowed since Scala 2.13.
To express the assignment expression, wrap it in brackets, e.g., `{ x = ... }`.
f2(x = 1) // error, no parameter named x. error message mentions change in 2.13
^
names-defaults-neg-213.scala:13: warning: a pure expression does nothing in statement position
f1(x = 1) // ok, named arg (value discard)
^
names-defaults-neg-213.scala:14: error: unknown parameter name: x
f2(x = 1) // error (no such parameter). no mention of new semantics in 2.13
^
two warnings found
two errors found
1 change: 1 addition & 0 deletions test/files/neg/names-defaults-neg-213.flags
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-Xsource:2.13
16 changes: 16 additions & 0 deletions test/files/neg/names-defaults-neg-213.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class C {
def f1(x: Unit): Int = 0
def f2(y: Unit): Int = 0

def t1 = {
var x = 0
f1(x = 1) // named arg in 2.13 (value discard), not ambiguous
f2(x = 1) // error, no parameter named x. error message mentions change in 2.13
}

def t2 = {
val x = 0
f1(x = 1) // ok, named arg (value discard)
f2(x = 1) // error (no such parameter). no mention of new semantics in 2.13
}
}
20 changes: 17 additions & 3 deletions test/files/neg/names-defaults-neg-warn.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ names-defaults-neg-warn.scala:11: warning: the parameter name s is deprecated: u
names-defaults-neg-warn.scala:12: warning: the parameter name x is deprecated: use s instead
deprNam2.g(x = "dlkjf")
^
error: No warnings can be incurred under -Xfatal-warnings.
two warnings found
one error found
names-defaults-neg-warn.scala:22: error: reference to x is ambiguous; it is both a method parameter and a variable in scope.
f1(x = 1) // 2.12: error, ambiguous (named arg or assign). 2.13: named arg
^
names-defaults-neg-warn.scala:23: warning: assignments in argument position are deprecated in favor of named arguments. Wrap the assignment in brackets, e.g., `{ x = ... }`.
f2(x = 1) // 2.12: deprecation warning, compiles. 2.13: error, no parameter named x
^
names-defaults-neg-warn.scala:34: warning: assignments in argument position are deprecated in favor of named arguments. Wrap the assignment in brackets, e.g., `{ x = ... }`.
synchronized(x = 1) // deprecation warning in 2.12, error in 2.13
^
names-defaults-neg-warn.scala:42: warning: a pure expression does nothing in statement position
f1(x = 1) // 2.12, 2.13: ok, named arg (value discard)
^
names-defaults-neg-warn.scala:43: error: reassignment to val
f2(x = 1) // 2.12, 2.13: error (no such parameter). no deprecation warning in 2.12, x is not a variable.
^
5 warnings found
two errors found
31 changes: 31 additions & 0 deletions test/files/neg/names-defaults-neg-warn.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,34 @@ object Test extends App {
deprNam2.g(x = "dlkjf")
deprNam2.g(s = new Object)
}

class C {
def f1(x: Unit): Unit = ()
def f2(y: Unit): Unit = ()

def t1 = {
var x = 0
f1(x = 1) // 2.12: error, ambiguous (named arg or assign). 2.13: named arg
f2(x = 1) // 2.12: deprecation warning, compiles. 2.13: error, no parameter named x

// all of the following are assignments to x

f1((x = 1))
f2((x = 1))
f1({ x = 1 })
f2({ x = 1 })
f1 { x = 1 }
f2 { x = 1 }

synchronized(x = 1) // deprecation warning in 2.12, error in 2.13
synchronized((x = 1)) // ok
synchronized({ x = 1 }) // ok
synchronized { x = 1 } // ok
}

def t2 = {
val x = 0
f1(x = 1) // 2.12, 2.13: ok, named arg (value discard)
f2(x = 1) // 2.12, 2.13: error (no such parameter). no deprecation warning in 2.12, x is not a variable.
}
}
4 changes: 3 additions & 1 deletion test/files/run/names-defaults.check
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ names-defaults.scala:269: warning: a pure expression does nothing in statement p
names-defaults.scala:269: warning: multiline expressions might require enclosing parentheses; a value can be silently discarded when Unit is expected
spawn(b = { val ttt = 1; ttt }, a = 0)
^
warning: there were four deprecation warnings; re-run with -deprecation for details
warning: there were four deprecation warnings
warning: there was one deprecation warning (since 2.12.4)
warning: there were 5 deprecation warnings in total; re-run with -deprecation for details
1: @
get: $
get: 2
Expand Down
0