Fix boxing/unboxing arguments and return values in method references

This commit is contained in:
Alexey Andreev 2023-11-19 20:00:06 +01:00
parent 4fc43a5597
commit 318d4bff93
2 changed files with 51 additions and 7 deletions

View File

@ -188,19 +188,35 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor
} else if (from instanceof ValueType.Primitive && to instanceof ValueType.Object) {
String primitiveClass = ((ValueType.Object) to).getClassName();
PrimitiveType toType = getWrappedPrimitive(primitiveClass);
var fromType = (ValueType.Primitive) from;
if (toType == null) {
return arg;
return arg.getProgramEmitter().invoke(fromType.getBoxedType().getClassName(), "valueOf",
fromType.getBoxedType(), arg);
}
arg = tryConvertArgument(arg, from, ValueType.primitive(toType));
return arg.getProgramEmitter().invoke(primitiveClass, "valueOf", to, arg);
} else if (from instanceof ValueType.Object && to instanceof ValueType.Primitive) {
String primitiveClass = ((ValueType.Object) from).getClassName();
PrimitiveType fromType = getWrappedPrimitive(primitiveClass);
if (fromType == null) {
return arg;
var fromClass = ((ValueType.Object) from).getClassName();
var primitiveType = (ValueType.Primitive) to;
if (fromClass.equals("java.lang.Object")) {
switch (primitiveType.getKind()) {
case BYTE:
case SHORT:
case INTEGER:
case LONG:
case FLOAT:
case DOUBLE:
arg = arg.cast(ValueType.object("java.lang.Number"));
break;
case BOOLEAN:
arg = arg.cast(ValueType.object("java.lang.Boolean"));
break;
case CHARACTER:
arg = arg.cast(ValueType.object("java.lang.Character"));
break;
}
arg = arg.invokeVirtual(primitiveName(fromType) + "Value", ValueType.primitive(fromType));
return tryConvertArgument(arg, ValueType.primitive(fromType), to);
}
return arg.invokeVirtual(primitiveName(primitiveType.getKind()) + "Value", primitiveType);
} else {
return arg.cast(to);
}

View File

@ -17,12 +17,15 @@ package org.teavm.vm;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.IntPredicate;
import java.util.function.Supplier;
import java.util.function.ToDoubleFunction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.junit.EachTestCompiledSeparately;
@ -80,6 +83,31 @@ public class LambdaTest {
Consumer<String> foo = bar -> { };
}
@Test
public void methodReferenceUnboxing() {
var map = Map.of(1, 23.0, 2, 42.0);
ToDoubleFunction<Integer> f = map::get;
assertEquals(23.0, f.applyAsDouble(1), 0.01);
assertNotEquals(24.0, f.applyAsDouble(1), 0.01);
assertEquals(42.0, f.applyAsDouble(2), 0.01);
var intMap = Map.of(1, 23, 2, 42);
ToDoubleFunction<Integer> g = intMap::get;
assertEquals(23.0, g.applyAsDouble(1), 0.01);
assertNotEquals(24.0, g.applyAsDouble(1), 0.01);
assertEquals(42.0, g.applyAsDouble(2), 0.01);
}
@Test
public void methodReferenceBoxing() {
java.util.function.Function<Integer, Object> f = this::intFunction;
assertEquals(25, f.apply(23));
}
private int intFunction(int a) {
return a + 2;
}
private String acceptIntPredicate(IntPredicate p) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; ++i) {