use of org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor in project ceylon by eclipse.
the class ValueImpl method initField.
private void initField(Object instance, Type valueType) {
org.eclipse.ceylon.model.typechecker.model.Value decl = (org.eclipse.ceylon.model.typechecker.model.Value) declaration.declaration;
String name = decl.getName();
if (decl instanceof JavaBeanValue) {
java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
if (javaClass == ceylon.language.Object.class || javaClass == ceylon.language.Basic.class || javaClass == ceylon.language.Identifiable.class) {
if ("string".equals(name) || "hash".equals(name)) {
// look it up on j.l.Object, getterName should work
javaClass = java.lang.Object.class;
} else {
throw Metamodel.newModelError("Object/Basic/Identifiable member not supported: " + name);
}
} else if (javaClass == ceylon.language.Throwable.class) {
if ("cause".equals(name) || "message".equals(name) || "suppressed".equals(name)) {
javaClass = instance.getClass();
isSuppressed = "suppressed".equals(name);
}
}
String getterName = ((JavaBeanValue) decl).getGetterName();
try {
Class<?>[] params;
if (!declaration.getStatic()) {
params = NO_PARAMS;
} else {
int numCapturedTypeParams = ((ClassOrInterface) declaration.declaration.getContainer()).getTypeParameters().size();
params = new Class[numCapturedTypeParams];
Arrays.fill(params, TypeDescriptor.class);
}
boolean isJavaArray = MethodHandleUtil.isJavaArray(javaClass);
if (isJavaArray)
params = MethodHandleUtil.getJavaArrayGetArrayParameterTypes(javaClass, getterName);
// if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
m.setAccessible(true);
getter = MethodHandles.lookup().unreflect(m);
java.lang.Class<?> getterType = m.getReturnType();
getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
if (instance != null && // XXXArray.getArray is static but requires an instance as first param
(isJavaArray || !Modifier.isStatic(m.getModifiers()))) {
getter = getter.bindTo(instance);
}
if (declaration.getStatic()) {
getter = getter.asType(MethodType.methodType(Object.class, params));
TypeDescriptor[] typeArguments = ((TypeDescriptor.Class) ((ClassOrInterfaceImpl<?>) container).$reifiedType).getTypeArguments();
getter = getter.asSpreader(TypeDescriptor[].class, typeArguments.length);
getter = getter.bindTo(typeArguments);
} else {
// we need to cast to Object because this is what comes out when calling it in $call
getter = getter.asType(MethodType.methodType(Object.class));
}
initSetter(decl, javaClass, getterType, instance, valueType);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
}
} else if (decl instanceof LazyValue) {
LazyValue lazyDecl = (LazyValue) decl;
java.lang.Class<?> javaClass = ((ReflectionClass) lazyDecl.classMirror).klass;
// FIXME: we should really save the getter name in the LazyDecl
String getterName = NamingBase.getGetterName(lazyDecl);
try {
// toplevels don't have inheritance
Method m = javaClass.getDeclaredMethod(getterName);
m.setAccessible(true);
getter = MethodHandles.lookup().unreflect(m);
java.lang.Class<?> getterType = m.getReturnType();
getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
// we need to cast to Object because this is what comes out when calling it in $call
getter = getter.asType(MethodType.methodType(Object.class));
initSetter(decl, javaClass, getterType, null, valueType);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
}
} else if (decl instanceof FieldValue) {
FieldValue fieldDecl = (FieldValue) decl;
java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
String fieldName = fieldDecl.getRealName();
if (MethodHandleUtil.isJavaArray(javaClass)) {
try {
Method method = Array.class.getDeclaredMethod("getLength", Object.class);
getter = MethodHandles.lookup().unreflect(method);
java.lang.Class<?> getterType = method.getReturnType();
getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
// this one is static but requires an instance a first param
if (instance != null)
getter = getter.bindTo(instance);
// we need to cast to Object because this is what comes out when calling it in $call
getter = getter.asType(MethodType.methodType(Object.class));
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
throw Metamodel.newModelError("Failed to find Array.getLength method for: " + decl, e);
}
} else {
try {
// fields are not inherited
Field f = javaClass.getDeclaredField(fieldName);
f.setAccessible(true);
getter = MethodHandles.lookup().unreflectGetter(f);
java.lang.Class<?> getterType = f.getType();
getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
if (instance != null && !Modifier.isStatic(f.getModifiers()))
getter = getter.bindTo(instance);
// we need to cast to Object because this is what comes out when calling it in $call
getter = getter.asType(MethodType.methodType(Object.class));
initSetter(decl, javaClass, getterType, instance, valueType);
} catch (NoSuchFieldException | SecurityException | IllegalAccessException e) {
throw Metamodel.newModelError("Failed to find field " + fieldName + " for: " + decl, e);
}
}
} else if (ModelUtil.isEnumeratedConstructor(decl)) {
java.lang.Class<?> javaClass = Metamodel.getJavaClass((org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) decl.getContainer());
String getterName = NamingBase.getGetterName(decl);
try {
Class<?>[] params = NO_PARAMS;
// if it is shared we may want to get an inherited getter, but if it's private we need the declared method to return it
Method m = decl.isShared() ? javaClass.getMethod(getterName, params) : javaClass.getDeclaredMethod(getterName, params);
m.setAccessible(true);
getter = MethodHandles.lookup().unreflect(m);
java.lang.Class<?> getterType = m.getReturnType();
getter = MethodHandleUtil.boxReturnValue(getter, getterType, valueType);
if (instance != null && // XXXArray.getArray is static but requires an instance as first param
(!Modifier.isStatic(m.getModifiers()))) {
getter = getter.bindTo(instance);
}
// we need to cast to Object because this is what comes out when calling it in $call
getter = getter.asType(MethodType.methodType(Object.class));
initSetter(decl, javaClass, getterType, instance, valueType);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {
throw Metamodel.newModelError("Failed to find getter method " + getterName + " for: " + decl, e);
}
} else
throw new StorageException("Attribute " + name + " is neither captured nor shared so it has no physical storage allocated and cannot be read by the metamodel");
}
use of org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor in project ceylon by eclipse.
the class RuntimeModuleManager method cachedIs.
public boolean cachedIs(Object o, TypeDescriptor type) {
TypeDescriptor instanceType = Metamodel.getTypeDescriptor(o);
String key = instanceType + "<:" + type;
Boolean cachedResult = isCache.get(key);
if (cachedResult != null) {
return cachedResult;
}
if (instanceType == null)
return false;
Type pt1 = getCachedType(instanceType);
Type pt2 = getCachedType(type);
boolean result = pt1.isSubtypeOf(pt2);
isCache.put(key, result);
return result;
}
use of org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor in project ceylon by eclipse.
the class TypeDescriptor method intersection.
public static TypeDescriptor intersection(TypeDescriptor... members) {
if (members == null || members.length == 0)
throw new AssertionError("members can't be null or empty");
members = flattenUnionOrIntersection(members, false);
TypeDescriptor single = getSingleTypeDescriptorIfUnique(members);
if (single != null)
return single;
members = removeDuplicates(members);
return new Intersection(members);
}
use of org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor in project ceylon by eclipse.
the class TypeDescriptor method union.
public static TypeDescriptor union(TypeDescriptor... members) {
if (members == null || members.length == 0)
throw new AssertionError("members can't be null or empty");
members = flattenUnionOrIntersection(members, true);
TypeDescriptor single = getSingleTypeDescriptorIfUnique(members);
if (single != null)
return single;
members = removeDuplicates(members);
// special-case for Tuples because we want to unwrap them even if someone constructs them manually
if (members.length == 2) {
TypeDescriptor alternative = null;
if (members[0].equals(Empty.$TypeDescriptor$))
alternative = members[1];
else if (members[1].equals(Empty.$TypeDescriptor$))
alternative = members[0];
if (alternative instanceof Tuple) {
// damn, so we have a []|[A] that we want to turn into a [A=]
Tuple tuple = (Tuple) alternative;
// trust the tuple on variadic, and same list of elements
return new Tuple(tuple.variadic, tuple.atLeastOne, 0, tuple.elements);
} else if (alternative instanceof Class) {
Class klass = (Class) alternative;
TypeDescriptor tuple = unwrapTupleType(klass.getKlass(), klass.useSiteVariance, klass.getTypeArguments(), true);
if (tuple != null)
return tuple;
}
}
return new Union(members);
}
use of org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor in project ceylon by eclipse.
the class TypeDescriptor method unwrapTupleType.
private static TypeDescriptor.Tuple unwrapTupleType(java.lang.Class<?> klass, Variance[] useSiteVariance, TypeDescriptor[] typeArguments, boolean allOptional) {
if (klass != ceylon.language.Tuple.class || (useSiteVariance != null && useSiteVariance != NO_VARIANCE))
return null;
if (typeArguments.length != 3)
return null;
List<TypeDescriptor> elementTypes = new LinkedList<TypeDescriptor>();
boolean variadic = false;
boolean atLeastOne = false;
int firstDefaulted = allOptional ? 0 : -1;
do {
TypeDescriptor first = typeArguments[1];
TypeDescriptor rest = typeArguments[2];
elementTypes.add(first);
if (rest.equals(Empty.$TypeDescriptor$)) {
// that's the last one
break;
} else if (rest instanceof TypeDescriptor.Tuple) {
Tuple restTuple = (Tuple) rest;
return combineTuples(elementTypes, firstDefaulted, restTuple);
} else if (rest instanceof TypeDescriptor.Class) {
Class restClass = (Class) rest;
if (restClass.getKlass() == ceylon.language.Tuple.class) {
// move to the next one
typeArguments = restClass.getTypeArguments();
// and loop
} else if (restClass.getKlass() == Sequence.class) {
// that's the last one
if (restClass.getTypeArguments().length != 1)
return null;
// add the sequence element type
elementTypes.add(restClass.getTypeArguments()[0]);
variadic = atLeastOne = true;
// and we're done
break;
} else if (restClass.getKlass() == Sequential.class) {
// that's the last one
if (restClass.getTypeArguments().length != 1)
return null;
// add the sequential element type
elementTypes.add(restClass.getTypeArguments()[0]);
variadic = true;
// and we're done
break;
} else {
// no idea
return null;
}
} else if (rest instanceof TypeDescriptor.Union) {
// could be an optional
Union restUnion = (Union) rest;
if (restUnion.members.length != 2)
return null;
TypeDescriptor alternative = null;
if (restUnion.members[0] == Empty.$TypeDescriptor$) {
alternative = restUnion.members[1];
} else if (restUnion.members[1] == Empty.$TypeDescriptor$) {
alternative = restUnion.members[0];
}
if (alternative == null)
return null;
// record the first defaulted if it's the first
if (firstDefaulted == -1) {
// so if we have N elements, N is the index of the first defaulted one (the next element)
firstDefaulted = elementTypes.size();
}
// now, it MUST be a tuple IIRC
if (alternative instanceof TypeDescriptor.Tuple) {
Tuple restTuple = (Tuple) alternative;
return combineTuples(elementTypes, firstDefaulted, restTuple);
} else if (alternative instanceof TypeDescriptor.Class) {
if (((TypeDescriptor.Class) alternative).getKlass() == ceylon.language.Tuple.class) {
// we're good, go on and loop
typeArguments = ((TypeDescriptor.Class) alternative).getTypeArguments();
} else {
// no idea
return null;
}
} else {
// no idea
return null;
}
} else {
// no idea
return null;
}
} while (true);
return new Tuple(variadic, atLeastOne, firstDefaulted, elementTypes.toArray(new TypeDescriptor[elementTypes.size()]));
}
Aggregations