Skip to content

Commit 44f13ef

Browse files
authored
Merge pull request #9420 from sjrd/enable-reflective-selectable-for-scala2-language-import
Scala 2 compat: enable reflectiveSelectable for language.reflectiveCalls.
2 parents 9a7ec05 + 0c159c8 commit 44f13ef

File tree

2 files changed

+145
-1
lines changed

2 files changed

+145
-1
lines changed

library/src/scala/Selectable.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
package scala
2-
import scala.reflect.ClassTag
32

43
/** A marker trait for objects that support structural selection via
54
* `selectDynamic` and `applyDynamic`
@@ -22,3 +21,15 @@ import scala.reflect.ClassTag
2221
* types of the method in the structural type.
2322
*/
2423
trait Selectable extends Any
24+
25+
object Selectable:
26+
/* Scala 2 compat + allowing for cross-compilation:
27+
* enable scala.reflect.Selectable.reflectiveSelectable when there is an
28+
* import scala.language.reflectiveCalls in scope.
29+
*/
30+
@deprecated(
31+
"import scala.reflect.Selectable.reflectiveSelectable instead of scala.language.reflectiveCalls",
32+
since = "3.0")
33+
implicit def reflectiveSelectableFromLangReflectiveCalls(x: Any)(
34+
using scala.languageFeature.reflectiveCalls): scala.reflect.Selectable =
35+
scala.reflect.Selectable.reflectiveSelectable(x)

tests/run/structural-compat.scala

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// the old reflectiveCalls still works and is equivalent to
2+
// import scala.reflect.Selectable.reflectiveSelectable
3+
import scala.language.reflectiveCalls
4+
5+
object Test {
6+
class C { type S = String; type I }
7+
class D extends C { type I = Int }
8+
9+
type Foo = {
10+
def sel0: Int
11+
def sel1: Int => Int
12+
def fun0(x: Int): Int
13+
14+
def fun1(x: Int)(y: Int): Int
15+
def fun2(x: Int): Int => Int
16+
def fun3(a1: Int, a2: Int, a3: Int)
17+
(a4: Int, a5: Int, a6: Int)
18+
(a7: Int, a8: Int, a9: Int): Int
19+
20+
def fun4(implicit x: Int): Int
21+
def fun5(x: Int)(implicit y: Int): Int
22+
23+
def fun6(x: C, y: x.S): Int
24+
def fun7(x: C, y: x.I): Int
25+
def fun8(y: C): y.S
26+
def fun9(y: C): y.I
27+
}
28+
29+
class Foo1 {
30+
def sel0: Int = 1
31+
def sel1: Int => Int = x => x
32+
def fun0(x: Int): Int = x
33+
34+
def fun1(x: Int)(y: Int): Int = x + y
35+
def fun2(x: Int): Int => Int = y => x * y
36+
def fun3(a1: Int, a2: Int, a3: Int)
37+
(a4: Int, a5: Int, a6: Int)
38+
(a7: Int, a8: Int, a9: Int): Int = -1
39+
40+
def fun4(implicit x: Int): Int = x
41+
def fun5(x: Int)(implicit y: Int): Int = x + y
42+
43+
def fun6(x: C, y: x.S): Int = 1
44+
def fun7(x: C, y: x.I): Int = 2
45+
def fun8(y: C): y.S = "Hello"
46+
def fun9(y: C): y.I = 1.asInstanceOf[y.I]
47+
}
48+
49+
class Foo2 extends scala.Selectable {
50+
def sel0: Int = 1
51+
def sel1: Int => Int = x => x
52+
def fun0(x: Int): Int = x
53+
54+
def fun1(x: Int)(y: Int): Int = x + y
55+
def fun2(x: Int): Int => Int = y => x * y
56+
def fun3(a1: Int, a2: Int, a3: Int)
57+
(a4: Int, a5: Int, a6: Int)
58+
(a7: Int, a8: Int, a9: Int): Int = -1
59+
60+
def fun4(implicit x: Int): Int = x
61+
def fun5(x: Int)(implicit y: Int): Int = x + y
62+
63+
def fun6(x: C, y: x.S): Int = 1
64+
def fun7(x: C, y: x.I): Int = 2
65+
def fun8(y: C): y.S = "Hello"
66+
def fun9(y: C): y.I = 1.asInstanceOf[y.I]
67+
}
68+
69+
def basic(x: Foo): Unit ={
70+
assert(x.sel0 == 1)
71+
assert(x.sel1(2) == 2)
72+
assert(x.fun0(3) == 3)
73+
74+
val f = x.sel1
75+
assert(f(3) == 3)
76+
}
77+
78+
def currying(x: Foo): Unit = {
79+
assert(x.fun1(1)(2) == 3)
80+
assert(x.fun2(1)(2) == 2)
81+
assert(x.fun3(1, 2, 3)(4, 5, 6)(7, 8, 9) == -1)
82+
}
83+
84+
def etaExpansion(x: Foo): Unit = {
85+
val f0 = x.fun0(_)
86+
assert(f0(2) == 2)
87+
88+
val f1 = x.fun0 _
89+
assert(f1(2) == 2)
90+
91+
val f2 = x.fun1(1)(_)
92+
assert(f2(2) == 3)
93+
94+
val f3 = x.fun1(1) _
95+
assert(f3(2) == 3)
96+
97+
val f4 = x.fun1(1)
98+
assert(f4(2) == 3)
99+
}
100+
101+
def implicits(x: Foo) = {
102+
implicit val y = 2
103+
assert(x.fun4 == 2)
104+
assert(x.fun5(1) == 3)
105+
}
106+
107+
// Limited support for dependant methods
108+
def dependent(x: Foo) = {
109+
val y = new D
110+
111+
assert(x.fun6(y, "Hello") == 1)
112+
// assert(x.fun7(y, 1) == 2) // error: No ClassTag available for x.I
113+
114+
val s = x.fun8(y)
115+
assert((s: String) == "Hello")
116+
117+
// val i = x.fun9(y) // error: rejected (blows up in pickler if not rejected)
118+
// assert((i: String) == "Hello") // error: Type mismatch: found: y.S(i); required: String
119+
}
120+
121+
def main(args: Array[String]): Unit = {
122+
basic(new Foo1)
123+
currying(new Foo1)
124+
etaExpansion(new Foo1)
125+
implicits(new Foo1)
126+
dependent(new Foo1)
127+
basic(new Foo2)
128+
currying(new Foo2)
129+
etaExpansion(new Foo2)
130+
implicits(new Foo2)
131+
dependent(new Foo2)
132+
}
133+
}

0 commit comments

Comments
 (0)