summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-07-29 15:38:50 +0000
committerPaul Phillips <paulp@improving.org>2011-07-29 15:38:50 +0000
commit4e488a60594664046c3449e1aa2239adca7a012e (patch)
treee02baffa12f57600c28e0109adf66e4ac0a00920 /src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
parentcda84e7f2145673e4e14cb886598fe19cd48585a (diff)
downloadscala-4e488a60594664046c3449e1aa2239adca7a012e.tar.gz
scala-4e488a60594664046c3449e1aa2239adca7a012e.tar.bz2
scala-4e488a60594664046c3449e1aa2239adca7a012e.zip
Added two new compiler options:
-Ywarn-adapted-args // also included in -Xlint -Yno-adapted-args The former warns when a () is inserted or an argument list is implicitly tupled. The latter errors under the same conditions. Using these options I found several bugs in the distribution which would otherwise be nearly impossible to spot. These bugs were innocuous (I think) but similar bugs could easily be (and have been) otherwise. Certain particularly threatening scenarios are at minimum warned about regardless of options given. Closes SI-4851, no review.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Adaptations.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Adaptations.scala82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
new file mode 100644
index 0000000000..3dee4650de
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
@@ -0,0 +1,82 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2011 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools.nsc
+package typechecker
+
+/** This trait provides logic for assessing the validity of argument
+ * adaptations, such as tupling, unit-insertion, widening, etc. Such
+ * logic is spread around the compiler, without much ability on the
+ * part of the user to tighten the potentially dangerous bits.
+ *
+ * TODO: unifying/consolidating said logic under consistent management.
+ *
+ * @author Paul Phillips
+ */
+trait Adaptations {
+ self: Analyzer =>
+
+ import global._
+ import definitions._
+
+ trait Adaptation {
+ self: Typer =>
+
+ def checkValidAdaptation(t: Tree, args: List[Tree]): Boolean = {
+ def applyArg = t match {
+ case Apply(_, arg :: Nil) => arg
+ case _ => EmptyTree
+ }
+ def callString = (
+ ( if (t.symbol.isConstructor) "new " else "" ) +
+ ( t.symbol.owner.decodedName ) +
+ ( if (t.symbol.isConstructor || t.symbol.name == nme.apply) "" else "." + t.symbol.decodedName )
+ )
+ def sigString = t.symbol.owner.decodedName + (
+ if (t.symbol.isConstructor) t.symbol.signatureString
+ else "." + t.symbol.decodedName + t.symbol.signatureString
+ )
+ def givenString = if (args.isEmpty) "<none>" else args.mkString(", ")
+ def adaptedArgs = if (args.isEmpty) "(): Unit" else args.mkString("(", ", ", "): " + applyArg.tpe)
+
+ def adaptWarning(msg: String) = context.warning(t.pos, msg +
+ "\n signature: " + sigString +
+ "\n given arguments: " + givenString +
+ "\n after adaptation: " + callString + "(" + adaptedArgs + ")"
+ )
+ // A one-argument method accepting Object (which may look like "Any"
+ // at this point if the class is java defined) is a "leaky target" for
+ // which we should be especially reluctant to insert () or auto-tuple.
+ def isLeakyTarget = {
+ val oneArgObject = t.symbol.paramss match {
+ case (param :: Nil) :: Nil => ObjectClass isSubClass param.tpe.typeSymbol
+ case _ => false
+ }
+ // Unfortunately various "universal" methods and the manner in which
+ // they are used limits our ability to enforce anything sensible until
+ // an opt-in compiler option is given.
+ oneArgObject && !(
+ isStringAddition(t.symbol)
+ || t.symbol.name == nme.equals_
+ || t.symbol.name == nme.EQ
+ || t.symbol.name == nme.NE
+ )
+ }
+
+ if (settings.noAdaptedArgs.value)
+ adaptWarning("No automatic adaptation here: use explicit parentheses.")
+ else if (settings.warnAdaptedArgs.value)
+ adaptWarning(
+ if (args.isEmpty) "Adapting argument list by inserting (): " + (
+ if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous."
+ else "this is unlikely to be what you want."
+ )
+ else "Adapting argument list by creating a " + args.size + "-tuple: this may not be what you want."
+ )
+
+ !settings.noAdaptedArgs.value
+ }
+ }
+}