Skip to content

Commit 7b712ff

Browse files
committed
Add test cases for implicit and dependant methods
Rejects all dependant methods used in structural type. They are pretty broken currently. Should be fixable
1 parent 010f684 commit 7b712ff

File tree

3 files changed

+110
-24
lines changed

3 files changed

+110
-24
lines changed

compiler/src/dotty/tools/dotc/typer/Dynamic.scala

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,20 @@ trait Dynamic { self: Typer with Applications =>
162162
structuralCall(nme.selectDynamic, Nil).asInstance(tpe)
163163

164164
case tpe: MethodType =>
165-
if (tpe.isParamDependent)
165+
def isDependentMethod(tpe: Type): Boolean = tpe match {
166+
case tpe: MethodType =>
167+
tpe.isParamDependent ||
168+
tpe.isResultDependent ||
169+
isDependentMethod(tpe.resultType)
170+
case _ =>
171+
false
172+
}
173+
174+
if (isDependentMethod(tpe))
166175
fail(name, i"has a method type with inter-parameter dependencies")
167176
else {
168177
val ctags = tpe.paramInfoss.flatten.map(pt =>
169-
implicitArgTree(defn.ClassTagType.appliedTo(pt :: Nil), fun.pos.endPos))
178+
implicitArgTree(defn.ClassTagType.appliedTo(pt.widenDealias :: Nil), fun.pos.endPos))
170179
structuralCall(nme.applyDynamic, ctags).asInstance(tpe.finalResultType)
171180
}
172181

tests/neg/structural.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,20 @@ object Test3 {
2020

2121
type G = { def foo(x: Int, y: Int): Unit }
2222
def j(x: G) = x.foo(???) // error: missing argument
23+
24+
class H { type S = String; type I }
25+
class I extends H { type I = Int }
26+
type Dep = {
27+
def fun1(x: H, y: x.S): Int
28+
def fun2(x: H, y: x.I): Int
29+
def fun3(y: H): y.S
30+
def fun4(y: H): y.I
31+
}
32+
def k(x: Dep) = {
33+
val y = new I
34+
x.fun1(y, "Hello")
35+
x.fun2(y, 1) // error
36+
x.fun3(y)
37+
x.fun4(y) // error
38+
}
2339
}

tests/run/structural.scala

Lines changed: 83 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,107 @@
11
import scala.reflect.Selectable.reflectiveSelectable
22

33
object Test {
4+
class C { type S = String; type I }
5+
class D extends C { type I = Int }
6+
47
type Foo = {
5-
def foo(x: Int)(y: Int): Int
6-
def bar(x: Int): Int => Int
7-
def bat(a1: Int, a2: Int, a3: Int)
8-
(a4: Int, a5: Int, a6: Int)
9-
(a7: Int, a8: Int, a9: Int): Int
10-
def baz(x: Int): Int
8+
def fun1(x: Int)(y: Int): Int
9+
def fun2(x: Int): Int => Int
10+
def fun3(a1: Int, a2: Int, a3: Int)
11+
(a4: Int, a5: Int, a6: Int)
12+
(a7: Int, a8: Int, a9: Int): Int
13+
def fun4(x: Int): Int
14+
def fun5(implicit x: Int): Int
15+
def fun6(x: Int)(implicit y: Int): Int
16+
17+
def fun7(x: C, y: x.S): Int
18+
def fun8(x: C, y: x.I): Int
19+
def fun9(y: C): y.S
20+
def fun10(y: C): y.I
1121
}
1222

1323
class FooI {
14-
def foo(x: Int)(y: Int): Int = x + y
15-
def bar(x: Int): Int => Int = y => x * y
16-
def bat(a1: Int, a2: Int, a3: Int)
17-
(a4: Int, a5: Int, a6: Int)
18-
(a7: Int, a8: Int, a9: Int): Int = -1
19-
def baz(x: Int): Int = x
24+
def fun1(x: Int)(y: Int): Int = x + y
25+
def fun2(x: Int): Int => Int = y => x * y
26+
def fun3(a1: Int, a2: Int, a3: Int)
27+
(a4: Int, a5: Int, a6: Int)
28+
(a7: Int, a8: Int, a9: Int): Int = -1
29+
def fun4(x: Int): Int = x
30+
def fun5(implicit x: Int): Int = x
31+
def fun6(x: Int)(implicit y: Int): Int = x + y
32+
33+
def fun7(x: C, y: x.S): Int = 1
34+
def fun8(x: C, y: x.I): Int = 2
35+
def fun9(y: C): y.S = "Hello"
36+
def fun10(y: C): y.I = 1.asInstanceOf[y.I]
37+
}
38+
39+
def currying(x: Foo): Unit = {
40+
assert(x.fun1(1)(2) == 3)
41+
assert(x.fun2(1)(2) == 2)
42+
assert(x.fun3(1, 2, 3)(4, 5, 6)(7, 8, 9) == -1)
43+
44+
val f1 = x.fun1(1)(_)
45+
assert(f1(2) == 3)
46+
47+
val f2 = x.fun1(1) _
48+
assert(f2(2) == 3)
49+
50+
val f3 = x.fun1(1)
51+
assert(f3(2) == 3)
52+
53+
val f4 = x.fun4
54+
assert(f4(1) == 1)
55+
56+
val f5 = x.fun4 _
57+
assert(f5(2) == 2)
2058
}
2159

22-
def test(x: Foo): Unit = {
23-
assert(x.foo(1)(2) == 3)
24-
assert(x.bar(1)(2) == 2)
25-
assert(x.bat(1, 2, 3)(4, 5, 6)(7, 8, 9) == -1)
60+
def etaExpansion(x: Foo): Unit = {
61+
assert(x.fun1(1)(2) == 3)
62+
assert(x.fun2(1)(2) == 2)
63+
assert(x.fun3(1, 2, 3)(4, 5, 6)(7, 8, 9) == -1)
2664

27-
val f1 = x.foo(1)(_)
65+
val f1 = x.fun1(1)(_)
2866
assert(f1(2) == 3)
2967

30-
val f2 = x.foo(1) _
68+
val f2 = x.fun1(1) _
3169
assert(f2(2) == 3)
3270

33-
val f3 = x.foo(1)
71+
val f3 = x.fun1(1)
3472
assert(f3(2) == 3)
3573

36-
val f4 = x.baz
74+
val f4 = x.fun4
3775
assert(f4(1) == 1)
3876

39-
val f5 = x.baz _
77+
val f5 = x.fun4 _
4078
assert(f5(2) == 2)
4179
}
4280

81+
def implicits(x: Foo) = {
82+
implicit val y = 2
83+
assert(x.fun5 == 2)
84+
assert(x.fun6(1) == 3)
85+
}
86+
87+
// Limited support for dependant methods
88+
def dependant(x: Foo) = {
89+
val y = new D
90+
91+
assert(x.fun7(y, "Hello") == 1)
92+
// assert(x.fun8(y, 1) == 2) // error: No ClassTag available for x.I
93+
94+
val s = x.fun9(y)
95+
assert((s: String) == "Hello")
96+
97+
// val i = x.fun10(y) // error: rejected (blows up in pickler if not rejected)
98+
// assert((i: String) == "Hello") // error: Type mismatch: found: y.S(i); required: String
99+
}
100+
43101
def main(args: Array[String]): Unit = {
44-
test(new FooI)
102+
currying(new FooI)
103+
etaExpansion(new FooI)
104+
implicits(new FooI)
105+
dependant(new FooI)
45106
}
46107
}

0 commit comments

Comments
 (0)