Search in sources :

Example 21 with TypeDescriptor

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");
}
Also used : ClassOrInterface(org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) Field(java.lang.reflect.Field) Metamodel(org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) Method(java.lang.reflect.Method) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) LazyValue(org.eclipse.ceylon.model.loader.model.LazyValue) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) FieldValue(org.eclipse.ceylon.model.loader.model.FieldValue) ReflectionClass(org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass) JavaBeanValue(org.eclipse.ceylon.model.loader.model.JavaBeanValue) StorageException(ceylon.language.meta.model.StorageException)

Example 22 with TypeDescriptor

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;
}
Also used : Type(org.eclipse.ceylon.model.typechecker.model.Type) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor)

Example 23 with TypeDescriptor

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);
}
Also used : TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) AssertionError(ceylon.language.AssertionError)

Example 24 with TypeDescriptor

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);
}
Also used : TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor) AssertionError(ceylon.language.AssertionError)

Example 25 with TypeDescriptor

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()]));
}
Also used : Sequence(ceylon.language.Sequence) LinkedList(java.util.LinkedList) TypeDescriptor(org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor)

Aggregations

TypeDescriptor (org.eclipse.ceylon.compiler.java.runtime.model.TypeDescriptor)46 Metamodel (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel)23 TypeInfo (org.eclipse.ceylon.compiler.java.metadata.TypeInfo)18 TypeParameters (org.eclipse.ceylon.compiler.java.metadata.TypeParameters)17 Sequential (ceylon.language.Sequential)13 ReifiedType (org.eclipse.ceylon.compiler.java.runtime.model.ReifiedType)12 Type (org.eclipse.ceylon.model.typechecker.model.Type)11 OpenType (ceylon.language.meta.declaration.OpenType)9 ArrayList (java.util.ArrayList)9 ObjectArrayIterable (org.eclipse.ceylon.compiler.java.language.ObjectArrayIterable)9 MemberClassImpl (org.eclipse.ceylon.compiler.java.runtime.metamodel.meta.MemberClassImpl)7 ClassDeclaration (ceylon.language.meta.declaration.ClassDeclaration)5 Functional (org.eclipse.ceylon.model.typechecker.model.Functional)5 AssertionError (ceylon.language.AssertionError)4 ClassDeclarationImpl (org.eclipse.ceylon.compiler.java.runtime.metamodel.decl.ClassDeclarationImpl)4 ClassImpl (org.eclipse.ceylon.compiler.java.runtime.metamodel.meta.ClassImpl)4 ReflectionClass (org.eclipse.ceylon.model.loader.impl.reflect.mirror.ReflectionClass)4 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)4 Metamodel.getTypeDescriptor (org.eclipse.ceylon.compiler.java.runtime.metamodel.Metamodel.getTypeDescriptor)3 LazyClass (org.eclipse.ceylon.model.loader.model.LazyClass)3