Ver Fonte

type deduction in lambda

Ranides Atterwim há 10 anos atrás
pai
commit
71d458def0

+ 4 - 4
assira.drafts/src/main/java/net/ranides/assira/reflection/LambdaParams.java

@@ -66,11 +66,11 @@ public class LambdaParams {
 	}
 	
 	public static Class<?> typeof(Function function) throws Exception {
-//		if(!function.getClass().isSynthetic()) {
-//			return typeof_generic(function);
-//		} else {
+		if(!function.getClass().isSynthetic()) {
+			return typeof_generic(function);
+		} else {
 			return typeof_lambda(function);
-//		}
+		}
 	}
 	
 	private static Class<?> typeof_lambda(Function function) {

+ 42 - 75
assira.junit/src/main/java/net/ranides/assira/junit/TestUtils.java

@@ -9,6 +9,7 @@ package net.ranides.assira.junit;
 
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
@@ -55,47 +56,55 @@ final class TestUtils {
     }
 	
 	public static Class<?> typeof(Function<?,?> function) {
-//		if(!function.getClass().isSynthetic()) {
-//			return typeof_generic(function);
-//		} else {
-			return typeof_lambda(function);
-//		}
+		Class<?> clazz = function.getClass();
+		if(!clazz.isSynthetic()) {
+			return typeof_generic(clazz);
+		} else {
+			return typeof_lambda(clazz);
+		}
 	}
 	
-	private static Class<?> typeof_lambda(Function<?,?> function) {
-		// Masakra, jeśli lambda jest closure'm, to jej "metoda" pobiera więcej niż 1 argument.
-		// Te argumenty są "bindowane" przez inne metody-gettery pomocnicze.
-		//
-		// Dałoby się te argumenty ignorować "mądrze", bo są listowane w ConstantPool,
-		// ale na razie po prostu weźmy pierwsze "coś", które ma więcej niż 1 argument
-		// i módlmy się, żeby to nie było żadne syntetyczne gówno.
-		
-		ConstantPool cp = Li.get(function.getClass());
-		
-		for(int i=0; i<cp.getSize(); i++) {
-			String[] info;
-			try {
-				info = cp.getMemberRefInfoAt(i);
-			} catch(Exception ex) {
-				continue;
-			}
-			
-			String parent = info[0];
-			String name = info[1];
-			if("java/lang/Object".equals(parent) || "java/lang/Class".equals(parent) || "<init>".equals(name)) {
-				continue;
+	private static Class<?> typeof_generic(Class<?> clazz) {
+		ParameterizedType it = getGenericInterface(clazz, Function.class);
+		java.lang.reflect.Type pt = it.getActualTypeArguments()[1];
+        if(pt instanceof Class<?>) {
+            return (Class<?>)pt;
+        }
+        if(pt instanceof ParameterizedType) {
+            return (Class<?>)(((ParameterizedType)pt).getRawType());
+        }
+        throw new AssertionError("Deduction of return type failed. Unsupported function: " + clazz);
+	}
+	
+	private static ParameterizedType getGenericInterface(Class<?> type, Class<?> intface) {
+		for(java.lang.reflect.Type t : type.getGenericInterfaces()) {
+			ParameterizedType pt = (ParameterizedType)t;
+			if( intface.equals(pt.getRawType()) ) {
+				return pt;
 			}
+		}
+		throw new AssertionError(type.getName() + " does not implement " + intface.getName());
+	}
+	
+	private static Class<?> typeof_lambda(Class<?> clazz) {
+		// dość generyczne filtrowanie, które chyba eliminuje różne cuda 
+		// związane z wewnętrzną implementacją lambdy. uwaga! to działa TYLKO
+		// dla lambdy.
+
+		ConstantPool cp = Li.get(clazz);
+		
+		for(int i=0, n=cp.getSize(); i<n; i++) {
 			try {
-				if(net.ranides.asm.Type.getArgumentTypes(info[2]).length < 1) {
-					continue;
+				Member member = cp.getMethodAt(i);
+				if(member instanceof Method) {
+					Method method = (Method)member;
+					return method.getReturnType();
 				}
-			} catch(Exception ex) {
+			} catch(IllegalArgumentException $0) {
 				continue;
 			}
-			
-			return vm2class(function.getClass().getClassLoader(), net.ranides.asm.Type.getReturnType(info[2]).getDescriptor());
 		}
-		throw new AssertionError("Deduction of return type failed. Unsupported lambda: " + function);
+		throw new AssertionError("Deduction of return type failed. Unsupported lambda: " + clazz);
 	}
 	
 	private static Class<?> typeof_supplier(Method method) throws AssertionError {
@@ -123,48 +132,6 @@ final class TestUtils {
         throw new AssertionError("You can't use wildcard generic types in method: " + method, cause4method(method, "Invalid declaration"));
     }
 	
-	@SuppressWarnings("PMD")
-    private static Class<?> vm2class(ClassLoader loader, String vmtype) {
-		try {
-			if(vmtype.startsWith("[")) {
-				return Array.newInstance(vm2class(loader, vmtype.substring(1)), 0).getClass();
-			}
-			if(vmtype.startsWith("L") && vmtype.endsWith(";")) {
-				return Class.forName(vmtype.substring(1,vmtype.length()-1).replace('/', '.'), false, loader);
-			}
-			if("Z".equals(vmtype)) {
-				return boolean.class;
-			}
-			if("B".equals(vmtype)) {
-				return byte.class;
-			}
-			if("C".equals(vmtype)) {
-				return char.class;
-			}
-			if("S".equals(vmtype)) {
-				return short.class;
-			}
-			if("I".equals(vmtype)) {
-				return int.class;
-			}
-			if("J".equals(vmtype)) {
-				return long.class;
-			}
-			if("F".equals(vmtype)) {
-				return float.class;
-			}
-			if("D".equals(vmtype)) {
-				return double.class;
-			}
-			if("V".equals(vmtype)) {
-				return void.class;
-			}
-		} catch(ClassNotFoundException cause) {
-			throw rethrow(cause);
-		}
-		throw new AssertionError("Unknown type: " + vmtype);
-    }
-	
 	public static Exception cause4method(Method method, String message) {
         Exception e = new Exception(message); // NOPMD
         e.setStackTrace(new StackTraceElement[]{