Skip to content

Commit 719e9a9

Browse files
author
Łukasz A.J. Wrona
authored
Merge pull request #4787 from smowton/smowton/feature/synthesise-lambda-classes
Synthesise lambda classes
2 parents aa5fcda + a316fd5 commit 719e9a9

40 files changed

+1081
-206
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface InterfaceDeclaringEquals {
2+
3+
public int f(int x);
4+
5+
public boolean equals(Object other);
6+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface InterfaceWithDefaults {
2+
3+
public int f(int x);
4+
5+
public default int g() { return 1; }
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface StubInterface {
2+
3+
public int f(int x);
4+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
interface StubSuperinterface extends StubInterface {}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public class Test {
2+
3+
public static void main() {
4+
5+
StubInterface stubInterface = (x -> x);
6+
StubSuperinterface stubSuperinterface = (x -> x);
7+
InterfaceDeclaringEquals interfaceDeclaringEquals = (x -> x);
8+
InterfaceWithDefaults interfaceWithDefaults = (x -> x);
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
Test.class
3+
--function Test.main --verbosity 10
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^ignoring invokedynamic at java::Test.main:\(\)V address 0 which produces a stub type java::StubInterface
8+
^ignoring invokedynamic at java::Test.main:\(\)V address 6 which produces type java::StubSuperinterface which should have exactly one abstract method but actually has 0.
9+
^ignoring invokedynamic at java::Test.main:\(\)V address 12 which produces type java::InterfaceDeclaringEquals which should have exactly one abstract method but actually has 2.
10+
^ignoring invokedynamic at java::Test.main:\(\)V address 18 which produces type java::InterfaceWithDefaults which should have exactly one abstract method but actually has 2.
11+
--
12+
--
13+
This exercises four cases that aren't currently supported: stub interfaces, stub
14+
superinterfaces, interfaces that declare methods also declared on
15+
java.lang.Object, and interfaces that provide default methods. All we require at
16+
this point is that jbmc shouldn't crash when these are seen.

jbmc/regression/jbmc/lambda1/B.class

-61 Bytes
Binary file not shown.

jbmc/regression/jbmc/lambda1/B.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
public class B {
2-
public int y;
2+
public int y;
33

4-
public static java.util.function.Function<Double, Double> dmul = x -> x * 3.1415;
4+
public static Function<Double, Double> dmul = x -> x * 1.5;
55

6-
public void set(int x) {
7-
y = x;
8-
}
6+
public void set(int x) { y = x; }
97
}
319 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
interface BiFunction<From1, From2, To> {
3+
4+
public To apply(From1 f1, From2 f2);
5+
}

jbmc/regression/jbmc/lambda1/C.class

0 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
@FunctionalInterface
22
interface CustomLambda<T> {
3-
boolean is_ok(T t);
3+
boolean is_ok(T t);
44
}
264 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
interface Function<From, To> {
3+
4+
public To apply(From f);
5+
}
0 Bytes
Binary file not shown.
3.43 KB
Binary file not shown.
+175-87
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,185 @@
1-
import java.util.function.*;
2-
31
public class Lambdatest {
42

5-
class A {
6-
int x;
7-
}
8-
9-
CustomLambda<Integer> custom = x -> true;
10-
BiFunction<Float, Integer, Integer> add = (x0, y0) -> x0.intValue() + y0;
11-
int z = 10;
12-
13-
A a;
14-
B b = new B();
15-
16-
public Integer g(Float x, Integer y, BiFunction<Float, Integer, Integer> fun) {
17-
return fun.apply(x, y);
18-
}
19-
20-
public int f(Float x, Integer y, Integer z) {
21-
Integer tmp = add.apply(x, y);
22-
Function<Integer, Integer> mul = (a) -> a * tmp;
23-
return mul.apply(z);
24-
}
25-
26-
public int i(int x) {
27-
int z = 5;
28-
Function<Integer, Integer> foo = (a) -> a * z;
29-
return foo.apply(x);
30-
}
31-
32-
public int j(int x) {
33-
Function<Integer, Integer> foo = (a) -> a * z;
34-
return foo.apply(x);
35-
}
36-
37-
public int k(int x) {
38-
a.x = 10;
39-
40-
Function<Integer, Integer> foo = (y) -> y * a.x;
41-
return foo.apply(x);
42-
}
43-
44-
public int l(int x) {
45-
b.y = 10;
46-
Function<Integer, Integer> foo = (y) -> {
47-
int r = y * b.y;
48-
b.set(r);
49-
return r;
50-
};
51-
b = new B();
52-
b.y = 14;
53-
return foo.apply(x);
54-
}
55-
56-
public int m(int x) {
57-
b.y = 10;
58-
Function<Integer, Integer> foo = (y) -> {
59-
int r = y * b.y;
60-
b.y = r;
61-
return r;
62-
};
63-
return foo.apply(x);
64-
}
65-
66-
// test static field of different class
67-
public double d(Double x) {
68-
return B.dmul.apply(x);
3+
class A {
4+
int x;
5+
}
6+
7+
CustomLambda<Integer> custom = x -> true;
8+
BiFunction<Float, Integer, Integer> add = (x0, y0) -> x0.intValue() + y0;
9+
int z = 10;
10+
11+
A a = new A();
12+
B b = new B();
13+
14+
public Integer captureNone(Float x, Integer y,
15+
BiFunction<Float, Integer, Integer> fun) {
16+
return fun.apply(x, y);
17+
}
18+
19+
public int captureReference(Float x, Integer y, Integer z) {
20+
Integer tmp = add.apply(x, y);
21+
Function<Integer, Integer> mul = (a) -> a * tmp;
22+
return mul.apply(z);
23+
}
24+
25+
public int captureInt(int x) {
26+
int z = 5;
27+
Function<Integer, Integer> foo = (a) -> a * z;
28+
return foo.apply(x);
29+
}
30+
31+
public int captureThisPrimitive(int x) {
32+
Function<Integer, Integer> foo = (a) -> a * z;
33+
return foo.apply(x);
34+
}
35+
36+
public int captureThisReference(int x) {
37+
a.x = 10;
38+
39+
Function<Integer, Integer> foo = (y) -> y * a.x;
40+
return foo.apply(x);
41+
}
42+
43+
public int captureAndCall(int x) {
44+
b.y = 10;
45+
Function<Integer, Integer> foo = (y) -> {
46+
int r = y * b.y;
47+
b.set(r);
48+
return r;
49+
};
50+
b = new B();
51+
b.y = 14;
52+
return foo.apply(x);
53+
}
54+
55+
public int captureAndAssign(int x) {
56+
b.y = 10;
57+
Function<Integer, Integer> foo = (y) -> {
58+
int r = y * b.y;
59+
b.y = r;
60+
return r;
61+
};
62+
return foo.apply(x);
63+
}
64+
65+
// test static field of different class
66+
public double callStatic(Double x) { return B.dmul.apply(x); }
67+
68+
public int capture2(Float a) { return add.apply(a, 1); }
69+
70+
public boolean custom(Integer i) { return custom.is_ok(i); }
71+
72+
public static void main(String[] args, int unknown) {
73+
Lambdatest lt = new Lambdatest();
74+
if (unknown == 0) {
75+
// should succeed
76+
assert lt.captureNone(1.0f, 2, (x, y) -> x.intValue() + y) == 3;
77+
} else if (unknown == 1) {
78+
// should fail
79+
assert lt.captureNone(1.0f, 2, (x, y) -> x.intValue() + y) == 4;
80+
} else if (unknown == 2) {
81+
assert lt.captureReference(1.0f, 2, 3) == 9; // should succeed
82+
} else if (unknown == 3) {
83+
assert lt.captureReference(1.0f, 2, 3) == 10; // should fail
84+
} else if (unknown == 4) {
85+
assert lt.captureInt(2) == 10; // should succeed
86+
} else if (unknown == 5) {
87+
assert lt.captureInt(2) == 11; // should fail
88+
} else if (unknown == 6) {
89+
assert lt.captureThisPrimitive(3) == 30; // should succeed
90+
} else if (unknown == 7) {
91+
assert lt.captureThisPrimitive(3) == 31; // should fail
92+
} else if (unknown == 8) {
93+
assert lt.captureThisReference(4) == 40; // should succeed
94+
} else if (unknown == 9) {
95+
assert lt.captureThisReference(4) == 41; // should fail
96+
} else if (unknown == 10) {
97+
assert lt.captureAndCall(5) == 70; // should succeed
98+
assert lt.b.y == 70; // check side-effects of l method
99+
} else if (unknown == 11) {
100+
assert lt.captureAndCall(5) == 51; // should fail
101+
} else if (unknown == 12) {
102+
assert lt.captureAndAssign(6) == 60; // should succeed
103+
assert lt.b.y == 60; // check side-effects of m method
104+
} else if (unknown == 13) {
105+
assert lt.captureAndAssign(6) == 61; // should fail
106+
} else if (unknown == 14) {
107+
assert lt.callStatic(7.0) == 10.5; // should succeed
108+
} else if (unknown == 15) {
109+
assert lt.callStatic(7.0) == 12; // should fail
110+
} else if (unknown == 16) {
111+
assert lt.capture2(8.0f) == 9; // should succeed
112+
} else if (unknown == 17) {
113+
assert lt.capture2(8.0f) == 10; // should fail
114+
} else if (unknown == 18) {
115+
assert lt.custom(9); // should succeed
116+
} else if (unknown == 19) {
117+
assert !lt.custom(9); // should fail
118+
// Test array capture
119+
} else if (unknown == 20) {
120+
int array[] = new int[3];
121+
Function<Integer, Integer> func = (x) -> x + array.length;
122+
assert func.apply(2) == 5; // should succeed
123+
} else if (unknown == 21) {
124+
int array[] = new int[3];
125+
Function<Integer, Integer> func = (x) -> x + array.length;
126+
assert func.apply(2) == 6; // should fail
127+
// Test reference array
128+
} else if (unknown == 22) {
129+
Integer array[] = new Integer[3];
130+
Function<Integer, Integer> func = (x) -> x + array.length;
131+
assert func.apply(2) == 5; // should succeed
132+
} else if (unknown == 23) {
133+
Integer array[] = new Integer[3];
134+
Function<Integer, Integer> func = (x) -> x + array.length;
135+
assert func.apply(2) == 6; // should fail
136+
// Test outer class capture
137+
} else if (unknown == 24) {
138+
Outer outer = new Outer();
139+
outer.value = 42;
140+
Outer.Inner inner = outer.new Inner();
141+
Function<Integer, Integer> getter = inner.getOuterGetter();
142+
assert (getter.apply(0) == 42); // should succeed
143+
} else if (unknown == 25) {
144+
Outer outer = new Outer();
145+
outer.value = 42;
146+
Outer.Inner inner = outer.new Inner();
147+
Function<Integer, Integer> getter = inner.getOuterGetter();
148+
assert (getter.apply(0) != 42); // should fail
149+
// Static intialized lambda
150+
} else if (unknown == 26) {
151+
assert StaticLambdas.id.apply(96) == 96; // should succeed
152+
} else if (unknown == 27) {
153+
assert StaticLambdas.id.apply(96) != 96; // should fail
154+
// Reference equality of the captured object
155+
} else if (unknown == 28) {
156+
Object object = new Object();
157+
Function<Integer, Object> lambda = (x) -> object;
158+
assert (lambda.apply(0) == object); // should succeed
159+
} else if (unknown == 29) {
160+
Object object = new Object();
161+
Function<Integer, Object> lambda = (x) -> object;
162+
assert (lambda.apply(0) != object); // should fail
69163
}
164+
}
70165

71-
public int capture2(Float a) {
72-
return add.apply(a, 1);
73-
}
166+
static void lambdaCaptureNondet(Integer value) {
167+
Function<Integer, Integer> func = (x) -> value;
168+
assert func.apply(0) == 42;
169+
}
170+
}
74171

75-
public boolean custom(Integer i) {
76-
return custom.is_ok(i);
77-
}
172+
class StaticLambdas {
173+
final static Function<Integer, Integer> id = x -> x;
174+
}
78175

79-
public static void main(String[] args) {
80-
// Uses all of the above test functions, to ensure they are loaded under
81-
// symex-driven loading:
82-
83-
Lambdatest lt = new Lambdatest();
84-
lt.f(0.0f, 0, 0);
85-
lt.i(0);
86-
lt.j(0);
87-
lt.k(0);
88-
lt.l(0);
89-
lt.m(0);
90-
}
176+
class Outer {
177+
int value;
178+
class Inner {
179+
Function<Integer, Integer> getOuterGetter() { return (x) -> value; }
180+
}
91181
}
92182

93183
class C implements CustomLambda<Integer> {
94-
public boolean is_ok(Integer i) {
95-
return true;
96-
}
184+
public boolean is_ok(Integer i) { return true; }
97185
}
2 KB
Binary file not shown.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public class Nondet {
2+
int x;
3+
int y;
4+
public static void test(Nondet nondet) {
5+
Function<Integer, Integer> lambda = (z) -> nondet.x + nondet.y + z;
6+
assert (lambda.apply(0) == 42);
7+
}
8+
public static void testPrimitiveArray(int[] ints) {
9+
Function<Integer, Integer> lambda = (index) -> ints[index];
10+
assert (lambda.apply(0) == 42);
11+
}
12+
public static void testReferenceArray(Nondet[] nondets) {
13+
Function<Integer, Integer> lambda = (index) -> nondets[index].x;
14+
assert (lambda.apply(0) == 42);
15+
}
16+
}
1.15 KB
Binary file not shown.
265 Bytes
Binary file not shown.
990 Bytes
Binary file not shown.
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
Nondet.class
3+
--function Nondet.test --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
line 6 assertion.*FAILURE$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Check that objects created by the object factory can be captured by a lambda
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Nondet.class
3+
--function Nondet.testPrimitiveArray --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
4+
line 10 assertion.*FAILURE$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Check that primitive arrays created by the object factory can be
10+
captured by a lambda

0 commit comments

Comments
 (0)