summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@typesafe.com>2016-02-08 18:24:43 -0800
committerAdriaan Moors <adriaan.moors@typesafe.com>2016-03-26 22:52:41 -0700
commit8433b6fa0e86dfdcd3db31b97844b14d65e45359 (patch)
tree08d2db915b88057ff1b16479e797bbca41a385ce /test
parent651d67cff7af581751257711ad99d318a5a2879a (diff)
downloadscala-8433b6fa0e86dfdcd3db31b97844b14d65e45359.tar.gz
scala-8433b6fa0e86dfdcd3db31b97844b14d65e45359.tar.bz2
scala-8433b6fa0e86dfdcd3db31b97844b14d65e45359.zip
Treat `Function` literals uniformly, expecting SAM or FunctionN.
They both compile to INDY/MetaLambdaFactory, except when they occur in a constructor call. (TODO: can we lift the ctor arg expression to a method and avoid statically synthesizing anonymous subclass altogether?) Typers: - no longer synthesize SAMs -- *adapt* a Function literal to the expected (SAM/FunctionN) type - Deal with polymorphic/existential sams (relevant tests: pos/t8310, pos/t5099.scala, pos/t4869.scala) We know where to find the result type, as all Function nodes have a FunctionN-shaped type during erasure. (Including function literals targeting a SAM type -- the sam type is tracked as the *expected* type.) Lift restriction on sam types being class types. It's enough that they dealias to one, like regular instance creation expressions. Contexts: - No longer need encl method hack for return in sam. Erasure: - erasure preserves SAM type for function nodes - Normalize sam to erased function type during erasure, otherwise we may box the function body from `$anonfun(args)` to `{$anonfun(args); ()}` because the expected type for the body is now `Object`, and thus `Unit` does not conform. Delambdafy: - must set static flag before calling createBoxingBridgeMethod - Refactored `createBoxingBridgeMethod` to wrap my head around boxing, reworked it to generalize from FunctionN's boxing needs to arbitrary LMF targets. Other refactorings: ThisReferringMethodsTraverser, TreeGen.
Diffstat (limited to 'test')
-rw-r--r--test/files/neg/sammy_restrictions.check5
-rw-r--r--test/files/neg/sammy_restrictions.scala2
-rw-r--r--test/files/pos/sammy_implicit.scala2
-rw-r--r--test/files/pos/sammy_poly.scala3
-rw-r--r--test/files/run/indylambda-boxing/test.scala7
-rw-r--r--test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala29
6 files changed, 33 insertions, 15 deletions
diff --git a/test/files/neg/sammy_restrictions.check b/test/files/neg/sammy_restrictions.check
index 8cc49f9aa9..0276f3a067 100644
--- a/test/files/neg/sammy_restrictions.check
+++ b/test/files/neg/sammy_restrictions.check
@@ -8,9 +8,6 @@ sammy_restrictions.scala:32: error: type mismatch;
required: TwoAbstract
((x: Int) => 0): TwoAbstract
^
-sammy_restrictions.scala:34: error: class type required but DerivedOneAbstract with OneAbstract found
- ((x: Int) => 0): NonClassType // "class type required". I think we should avoid SAM translation here.
- ^
sammy_restrictions.scala:35: error: type mismatch;
found : Int => Int
required: NoEmptyConstructor
@@ -46,4 +43,4 @@ sammy_restrictions.scala:44: error: type mismatch;
required: PolyMethod
((x: Int) => 0): PolyMethod
^
-10 errors found
+9 errors found
diff --git a/test/files/neg/sammy_restrictions.scala b/test/files/neg/sammy_restrictions.scala
index d003cfaf36..101342ad0b 100644
--- a/test/files/neg/sammy_restrictions.scala
+++ b/test/files/neg/sammy_restrictions.scala
@@ -31,7 +31,7 @@ object Test {
(() => 0) : NoAbstract
((x: Int) => 0): TwoAbstract
((x: Int) => 0): DerivedOneAbstract // okay
- ((x: Int) => 0): NonClassType // "class type required". I think we should avoid SAM translation here.
+ ((x: Int) => 0): NonClassType // okay -- we also allow type aliases in instantiation expressions, if they resolve to a class type
((x: Int) => 0): NoEmptyConstructor
((x: Int) => 0): OneEmptyConstructor // okay
((x: Int) => 0): OneEmptySecondaryConstructor // derived class must have an empty *primary* to call.
diff --git a/test/files/pos/sammy_implicit.scala b/test/files/pos/sammy_implicit.scala
index c9c2519bab..e4b82df4cc 100644
--- a/test/files/pos/sammy_implicit.scala
+++ b/test/files/pos/sammy_implicit.scala
@@ -6,5 +6,5 @@ abstract class SamImplicitConvert {
implicit def conv(xs: Array[Int]): Lst[Int]
- val encoded = flatMap (_.getBytes)
+ def encoded = flatMap (_.getBytes)
}
diff --git a/test/files/pos/sammy_poly.scala b/test/files/pos/sammy_poly.scala
index c629be7166..75ee36f654 100644
--- a/test/files/pos/sammy_poly.scala
+++ b/test/files/pos/sammy_poly.scala
@@ -1,7 +1,8 @@
// test synthesizeSAMFunction where the sam type is not fully defined
class T {
trait F[T, U] { def apply(x: T): U }
+// type F[T, U] = T => U
// NOTE: the f(x) desugaring for now assumes the single abstract method is called 'apply'
def app[T, U](x: T)(f: F[T, U]): U = f(x)
app(1)(x => List(x))
-} \ No newline at end of file
+}
diff --git a/test/files/run/indylambda-boxing/test.scala b/test/files/run/indylambda-boxing/test.scala
index cc0a460640..82f8d2f497 100644
--- a/test/files/run/indylambda-boxing/test.scala
+++ b/test/files/run/indylambda-boxing/test.scala
@@ -2,15 +2,16 @@ class Capture
class Test {
def test1 = (i: Int) => ""
def test2 = (i: VC) => i
- def test3 = (i: Int) => i
+ def test3 = (i: Int) => i // not adapted, specialized
- def test4 = {val c = new Capture; (i: Int) => {(c, Test.this.toString); 42} }
+ def test4 = {val c = new Capture; (i: Int) => {(c, Test.this.toString); 42} } // not adapted, specialized
def test5 = {val c = new Capture; (i: VC) => (c, Test.this.toString) }
def test6 = {val c = new Capture; (i: Int) => (c, Test.this.toString) }
def test7 = {val vc = new Capture; (i: Int) => vc }
- def test8 = {val c = 42; (s: String) => (s, c)}
+ def test8 = {val c = 42; (s: String) => (s, c)} // not adapted
def test9 = {val c = 42; (s: String) => ()}
+ def test10 = {(s: List[String]) => ()}
}
object Test {
diff --git a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
index 758566fe53..d29f6b0a13 100644
--- a/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
+++ b/test/junit/scala/tools/nsc/backend/jvm/IndyLambdaTest.scala
@@ -31,25 +31,44 @@ class IndyLambdaTest extends ClearAfterClass {
case _ => Nil
}.head
}
+
+ val obj = "Ljava/lang/Object;"
+ val str = "Ljava/lang/String;"
+
// unspecialized functions that have a primitive in parameter or return position
// give rise to a "boxing bridge" method (which has the suffix `$adapted`).
// This is because Scala's unboxing of null values gives zero, whereas Java's throw a NPE.
// 1. Here we show that we are calling the boxing bridge (the lambda bodies here are compiled into
// methods of `(I)Ljava/lang/Object;` / `(I)Ljava/lang/Object;` respectively.)
- assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Int) => new Object"))
- assertEquals("(Ljava/lang/Object;)Ljava/lang/Object;", implMethodDescriptorFor("(x: Object) => 0"))
+ assertEquals(s"($obj)$obj", implMethodDescriptorFor("(x: Int) => new Object"))
+ assertEquals(s"($obj)$obj", implMethodDescriptorFor("(x: Object) => 0"))
// 2a. We don't need such adaptations for parameters or return values with types that differ
// from Object due to other generic substitution, LambdaMetafactory will downcast the arguments.
- assertEquals("(Ljava/lang/String;)Ljava/lang/String;", implMethodDescriptorFor("(x: String) => x"))
+ assertEquals(s"($str)$str", implMethodDescriptorFor("(x: String) => x"))
// 2b. Testing 2a. in combination with 1.
- assertEquals("(Ljava/lang/Object;)Ljava/lang/String;", implMethodDescriptorFor("(x: Int) => \"\""))
- assertEquals("(Ljava/lang/String;)Ljava/lang/Object;", implMethodDescriptorFor("(x: String) => 0"))
+ assertEquals(s"($obj)$str", implMethodDescriptorFor("(x: Int) => \"\""))
+ assertEquals(s"($str)$obj", implMethodDescriptorFor("(x: String) => 0"))
// 3. Specialized functions, don't need any of this as they implement a method like `apply$mcII$sp`,
// and the (un)boxing is handled in the base class in code emitted by scalac.
assertEquals("(I)I", implMethodDescriptorFor("(x: Int) => x"))
+
+ // non-builtin sams are like specialized functions
+ compileClasses(compiler)("class VC(private val i: Int) extends AnyVal; trait FunVC { def apply(a: VC): VC }")
+ assertEquals("(I)I", implMethodDescriptorFor("((x: VC) => x): FunVC"))
+
+ compileClasses(compiler)("trait Fun1[T, U] { def apply(a: T): U }")
+ assertEquals(s"($obj)$str", implMethodDescriptorFor("(x => x.toString): Fun1[Int, String]"))
+ assertEquals(s"($obj)$obj", implMethodDescriptorFor("(x => println(x)): Fun1[Int, Unit]"))
+ assertEquals(s"($obj)$str", implMethodDescriptorFor("((x: VC) => \"\") : Fun1[VC, String]"))
+ assertEquals(s"($str)$obj", implMethodDescriptorFor("((x: String) => new VC(0)) : Fun1[String, VC]"))
+
+ compileClasses(compiler)("trait Coll[A, Repr] extends Any")
+ compileClasses(compiler)("final class ofInt(val repr: Array[Int]) extends AnyVal with Coll[Int, Array[Int]]")
+
+ assertEquals(s"([I)$obj", implMethodDescriptorFor("((xs: Array[Int]) => new ofInt(xs)): Array[Int] => Coll[Int, Array[Int]]"))
}
}