aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-03-16 12:39:56 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2014-03-20 13:02:29 +0100
commit574a148fd561a793ee522c2be18ee02214236d80 (patch)
tree34d99eaeed0a35d549c04d8db3ec409e9293baed /src/dotty/tools/dotc
parentbff6b093d28bfc6918fa86d640353ba60b1a24e4 (diff)
downloaddotty-574a148fd561a793ee522c2be18ee02214236d80.tar.gz
dotty-574a148fd561a793ee522c2be18ee02214236d80.tar.bz2
dotty-574a148fd561a793ee522c2be18ee02214236d80.zip
Added auto-tupling.
Auto-tupling should satisfy the following spec. 1. An application `f(args)` where `f` is a non-overloaded method which has a single, non-repeated parameter as its first parameter list and where args consists of two or more arguments is expanded to `f((args))`. 2. A constructor pattern `C(args)` where `C.unapply` is a non-overloaded method which has a single, non-repeated parameter as its first parameter list and where args consists of two or more arguments is expanded to `C((args))`. Auto-tupling can be disabled by language feature "noAutoTupling". Conflicts: test/dotc/tests.scala
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala5
-rw-r--r--src/dotty/tools/dotc/core/Types.scala7
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala16
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala14
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala12
6 files changed, 51 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 5c2890f29..bcf2bb74c 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -215,7 +215,7 @@ class Definitions {
lazy val JavaSerializableClass = ctx.requiredClass("java.lang.Serializable")
lazy val ComparableClass = ctx.requiredClass("java.lang.Comparable")
lazy val ProductClass = ctx.requiredClass("scala.Product")
- lazy val LanguageModuleClass = ctx.requiredModule("dotty.language").moduleClass
+ lazy val LanguageModuleClass = ctx.requiredModule("dotty.language").moduleClass.asClass
// Annotation base classes
lazy val AnnotationClass = ctx.requiredClass("scala.annotation.Annotation")
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 4ace0bebe..22a86766b 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -5,6 +5,7 @@ import Contexts._, Types._, Symbols._, Names._, Flags._, Scopes._
import SymDenotations._
import config.Printers._
import Decorators._
+import StdNames._
import util.SimpleMap
trait TypeOps { this: Context =>
@@ -300,6 +301,10 @@ trait TypeOps { this: Context =>
def hasOption = ctx.base.settings.language.value exists (s => s == featureName || s == "_")
hasImport || hasOption
}
+
+ /** Is auto-tupling enabled? */
+ def canAutoTuple =
+ !featureEnabled(defn.LanguageModuleClass, nme.noAutoTupling)
}
object TypeOps {
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 6dda937d2..a0293d50a 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -685,6 +685,13 @@ object Types {
case _ => Nil
}
+ /** The parameter types in the first parameter section of a PolyType or MethodType, Empty list for others */
+ final def firstParamTypes: List[Type] = this match {
+ case mt: MethodType => mt.paramTypes
+ case pt: PolyType => pt.resultType.firstParamTypes
+ case _ => Nil
+ }
+
/** Is this either not a method at all, or a parameterless method? */
final def isParameterless: Boolean = this match {
case mt: MethodType => false
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index feaf678a2..4d26532d6 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -434,8 +434,17 @@ trait Applications extends Compatibility { self: Typer =>
def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
def realApply(implicit ctx: Context): Tree = track("realApply") {
- val proto = new FunProto(tree.args, pt, this)
+ var proto = new FunProto(tree.args, pt, this)
val fun1 = typedExpr(tree.fun, proto)
+
+ // Warning: The following line is dirty and fragile. We record that auto-tupling was demanded as
+ // a side effect in adapt. If it was, we assume the tupled proto-type in the rest of the application.
+ // This crucially relies on he fact that `proto` is used only in a single call of `adapt`,
+ // otherwise we would get possible cross-talk between different `adapt` calls using the same
+ // prototype. A cleaner alternative would be to return a modified prototype from `adapt` together with
+ // a modified tree but this would be more convoluted and less efficient.
+ if (proto.isTupled) proto = proto.tupled
+
methPart(fun1).tpe match {
case funRef: TermRef =>
tryEither { implicit ctx =>
@@ -676,7 +685,10 @@ trait Applications extends Compatibility { self: Typer =>
var argTypes = unapplyArgs(unapplyApp.tpe)
for (argType <- argTypes) assert(!argType.isInstanceOf[TypeBounds], unapplyApp.tpe.show)
val bunchedArgs = argTypes match {
- case argType :: Nil if argType.isRepeatedParam => untpd.SeqLiteral(args) :: Nil
+ case argType :: Nil =>
+ if (argType.isRepeatedParam) untpd.SeqLiteral(args) :: Nil
+ else if (args.lengthCompare(1) > 0 && ctx.canAutoTuple) untpd.Tuple(args) :: Nil
+ else args
case _ => args
}
if (argTypes.length != bunchedArgs.length) {
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index b4068408b..74be3f4cd 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -187,6 +187,20 @@ object ProtoTypes {
typer.adapt(targ, formal)
}
+ private var myTupled: Type = NoType
+
+ /** The same proto-type but with all arguments combined in a single tuple */
+ def tupled: FunProto = myTupled match {
+ case pt: FunProto =>
+ pt
+ case _ =>
+ myTupled = new FunProto(untpd.Tuple(args) :: Nil, resultType, typer)
+ tupled
+ }
+
+ /** Somebody called the `tupled` method of this prototype */
+ def isTupled: Boolean = myTupled.isInstanceOf[FunProto]
+
override def toString = s"FunProto(${args mkString ","} => $resultType)"
def map(tm: TypeMap)(implicit ctx: Context): FunProto =
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index 17c77be89..f961a4544 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1072,8 +1072,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
}
}
- def adaptToArgs(wtp: Type, pt: FunProto) = wtp match {
- case _: MethodType | _: PolyType => tree
+ def adaptToArgs(wtp: Type, pt: FunProto): Tree = wtp match {
+ case _: MethodType | _: PolyType =>
+ def isUnary = wtp.firstParamTypes match {
+ case ptype :: Nil => !ptype.isRepeatedParam
+ case _ => false
+ }
+ if (pt.args.lengthCompare(1) > 0 && isUnary && ctx.canAutoTuple)
+ adaptToArgs(wtp, pt.tupled)
+ else
+ tree
case _ => tryInsertApply(tree, pt) {
val more = tree match {
case Apply(_, _) => " more"