summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2013-10-03 23:02:27 -0700
committerAdriaan Moors <adriaan.moors@typesafe.com>2013-10-04 10:55:17 -0700
commit67062db57c1abef88e0049dac5d82d4f13375a48 (patch)
tree69cebe4522d71b8c9241ab887a486382106a6c3e /src
parent657e85fe2412cdadc5ee9dc348159b32dcdfcba7 (diff)
downloadscala-67062db57c1abef88e0049dac5d82d4f13375a48.tar.gz
scala-67062db57c1abef88e0049dac5d82d4f13375a48.tar.bz2
scala-67062db57c1abef88e0049dac5d82d4f13375a48.zip
Single Abstract Method support: synthesize SAMs
Under `-Xexperimental`, `typedFunction` invokes `synthesizeSAMFunction` when the expected type for the function literal (`pt`) is not the built-in `FunctionN` type of the expected arity, but `pt` does have a SAM with the expected number of arguments. PS: We'll require `import language.sam` instead of `-Xexperimental`, as soon as the SIP is ready and there are more tests.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala54
1 files changed, 44 insertions, 10 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 79039e3436..dfd962e13e 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2846,18 +2846,45 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
block
}
-
+ /** Type check a function literal.
+ *
+ * Based on the expected type pt, potentially synthesize an instance of
+ * - PartialFunction,
+ * - a type with a Single Abstract Method (under -Xexperimental for now).
+ */
private def typedFunction(fun: Function, mode: Mode, pt: Type): Tree = {
val numVparams = fun.vparams.length
- if (numVparams > definitions.MaxFunctionArity)
- return MaxFunctionArityError(fun)
+ val FunctionSymbol =
+ if (numVparams > definitions.MaxFunctionArity) NoSymbol
+ else FunctionClass(numVparams)
- val FunctionSymbol = FunctionClass(numVparams)
- val (argpts, respt) = pt baseType FunctionSymbol match {
- case TypeRef(_, FunctionSymbol, args :+ res) => (args, res)
- case _ => (fun.vparams map (_ => NoType), WildcardType)
- }
- if (argpts.lengthCompare(numVparams) != 0)
+ /* The Single Abstract Member of pt, unless pt is the built-in function type of the expected arity,
+ * as `(a => a): Int => Int` should not (yet) get the sam treatment.
+ */
+ val sam =
+ if (!settings.Xexperimental || pt.typeSymbol == FunctionSymbol) NoSymbol
+ else samOf(pt)
+
+ /* The SAM case comes first so that this works:
+ * abstract class MyFun extends (Int => Int)
+ * (a => a): MyFun
+ *
+ * Note that the arity of the sam must correspond to the arity of the function.
+ */
+ val (argpts, respt) =
+ if (sam.exists && sameLength(sam.info.params, fun.vparams)) {
+ val samInfo = pt memberInfo sam
+ (samInfo.paramTypes, samInfo.resultType)
+ } else {
+ pt baseType FunctionSymbol match {
+ case TypeRef(_, FunctionSymbol, args :+ res) => (args, res)
+ case _ => (fun.vparams map (_ => NoType), WildcardType)
+ }
+ }
+
+ if (!FunctionSymbol.exists)
+ MaxFunctionArityError(fun)
+ else if (argpts.lengthCompare(numVparams) != 0)
WrongNumberOfParametersError(fun, argpts)
else {
foreach2(fun.vparams, argpts) { (vparam, argpt) =>
@@ -2868,7 +2895,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
fun match {
case etaExpansion(vparams, fn, args) =>
silent(_.typed(fn, mode.forFunMode, pt)) filter (_ => context.undetparams.isEmpty) map { fn1 =>
- // if context,undetparams is not empty, the function was polymorphic,
+ // if context.undetparams is not empty, the function was polymorphic,
// so we need the missing arguments to infer its type. See #871
//println("typing eta "+fun+":"+fn1.tpe+"/"+context.undetparams)
val ftpe = normalize(fn1.tpe) baseType FunctionClass(numVparams)
@@ -2896,6 +2923,13 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (p.tpt.tpe == null) p.tpt setType outerTyper.typedType(p.tpt).tpe
outerTyper.synthesizePartialFunction(p.name, p.pos, fun.body, mode, pt)
+
+ // Use synthesizeSAMFunction to expand `(p1: T1, ..., pN: TN) => body`
+ // to an instance of the corresponding anonymous subclass of `pt`.
+ case _ if sam.exists =>
+ newTyper(context.outer).synthesizeSAMFunction(sam, fun, respt, pt, mode)
+
+ // regular Function
case _ =>
val vparamSyms = fun.vparams map { vparam =>
enterSym(context, vparam)