summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala
diff options
context:
space:
mode:
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
+ }
+ }
+}