Search in sources :

Example 1 with TypeParameterMirror

use of org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror in project ceylon by eclipse.

the class AbstractModelLoader method setTypeParametersFromAnnotations.

// from our annotation
private void setTypeParametersFromAnnotations(Scope scope, List<TypeParameter> params, AnnotatedMirror mirror, List<AnnotationMirror> typeParameterAnnotations, List<TypeParameterMirror> typeParameterMirrors) {
    // We must first add every type param, before we resolve the bounds, which can
    // refer to type params.
    String selfTypeName = getSelfTypeFromAnnotations(mirror);
    int i = 0;
    for (AnnotationMirror typeParamAnnotation : typeParameterAnnotations) {
        TypeParameter param = new TypeParameter();
        param.setUnit(scope.getUnit());
        param.setContainer(scope);
        param.setScope(scope);
        ModelUtil.setVisibleScope(param);
        param.setDeclaration((Declaration) scope);
        // let's not trigger the lazy-loading if we're completing a LazyClass/LazyInterface
        if (scope instanceof LazyContainer)
            ((LazyContainer) scope).addMember(param);
        else
            // must be a method
            scope.addMember(param);
        param.setName((String) typeParamAnnotation.getValue("value"));
        param.setExtendedType(typeFactory.getAnythingType());
        if (i < typeParameterMirrors.size()) {
            TypeParameterMirror typeParameterMirror = typeParameterMirrors.get(i);
            param.setNonErasedBounds(hasNonErasedBounds(typeParameterMirror));
        }
        String varianceName = (String) typeParamAnnotation.getValue("variance");
        if (varianceName != null) {
            if (varianceName.equals("IN")) {
                param.setContravariant(true);
            } else if (varianceName.equals("OUT"))
                param.setCovariant(true);
        }
        // If this is a self type param then link it to its type's declaration
        if (param.getName().equals(selfTypeName)) {
            param.setSelfTypedDeclaration((TypeDeclaration) scope);
        }
        params.add(param);
        i++;
    }
    Module moduleScope = ModelUtil.getModuleContainer(scope);
    // Now all type params have been set, we can resolve the references parts
    Iterator<TypeParameter> paramsIterator = params.iterator();
    for (AnnotationMirror typeParamAnnotation : typeParameterAnnotations) {
        TypeParameter param = paramsIterator.next();
        @SuppressWarnings("unchecked") List<String> satisfiesAttribute = (List<String>) typeParamAnnotation.getValue("satisfies");
        setListOfTypes(param.getSatisfiedTypes(), satisfiesAttribute, scope, moduleScope, "type parameter '" + param.getName() + "' satisfied types");
        @SuppressWarnings("unchecked") List<String> caseTypesAttribute = (List<String>) typeParamAnnotation.getValue("caseTypes");
        if (caseTypesAttribute != null && !caseTypesAttribute.isEmpty())
            param.setCaseTypes(new LinkedList<Type>());
        setListOfTypes(param.getCaseTypes(), caseTypesAttribute, scope, moduleScope, "type parameter '" + param.getName() + "' case types");
        String defaultValueAttribute = (String) typeParamAnnotation.getValue("defaultValue");
        if (defaultValueAttribute != null && !defaultValueAttribute.isEmpty()) {
            Type decodedType = decodeType(defaultValueAttribute, scope, moduleScope, "type parameter '" + param.getName() + "' defaultValue");
            param.setDefaultTypeArgument(decodedType);
            param.setDefaulted(true);
        }
    }
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) LinkedList(java.util.LinkedList) AnnotationMirror(org.eclipse.ceylon.model.loader.mirror.AnnotationMirror) LazyContainer(org.eclipse.ceylon.model.loader.model.LazyContainer) Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) TypeParameterMirror(org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror) List(java.util.List) ParameterList(org.eclipse.ceylon.model.typechecker.model.ParameterList) ArrayList(java.util.ArrayList) LinkedList(java.util.LinkedList) Module(org.eclipse.ceylon.model.typechecker.model.Module) LazyModule(org.eclipse.ceylon.model.loader.model.LazyModule)

Example 2 with TypeParameterMirror

use of org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror in project ceylon by eclipse.

the class JavacUtil method getTypeParameters.

public static List<TypeParameterMirror> getTypeParameters(Symbol symbol) {
    try {
        org.eclipse.ceylon.langtools.tools.javac.util.List<TypeVariableSymbol> typeParameters = symbol.getTypeParameters();
        List<TypeParameterMirror> ret = new ArrayList<TypeParameterMirror>(typeParameters.size());
        for (TypeVariableSymbol typeParameter : typeParameters) ret.add(new JavacTypeParameter(typeParameter));
        return ret;
    } catch (CompletionFailure x) {
        throw new ModelResolutionException("Failed to load type parameters", x);
    }
}
Also used : ModelResolutionException(org.eclipse.ceylon.model.loader.ModelResolutionException) TypeParameterMirror(org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror) CompletionFailure(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.CompletionFailure) ArrayList(java.util.ArrayList) TypeVariableSymbol(org.eclipse.ceylon.langtools.tools.javac.code.Symbol.TypeVariableSymbol)

Example 3 with TypeParameterMirror

use of org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror in project ceylon by eclipse.

the class AbstractModelLoader method setTypeParameters.

// from java type info
private void setTypeParameters(Scope scope, List<TypeParameter> params, List<TypeParameterMirror> typeParameters, boolean isCeylon) {
    // refer to type params.
    for (TypeParameterMirror typeParam : typeParameters) {
        TypeParameter param = new TypeParameter();
        param.setUnit(scope.getUnit());
        param.setContainer(scope);
        param.setScope(scope);
        ModelUtil.setVisibleScope(param);
        param.setDeclaration((Declaration) scope);
        // let's not trigger the lazy-loading if we're completing a LazyClass/LazyInterface
        if (scope instanceof LazyContainer)
            ((LazyContainer) scope).addMember(param);
        else
            // must be a method
            scope.addMember(param);
        param.setName(typeParam.getName());
        param.setExtendedType(typeFactory.getAnythingType());
        params.add(param);
    }
    boolean needsObjectBounds = !isCeylon && scope instanceof Function;
    // Now all type params have been set, we can resolve the references parts
    Iterator<TypeParameter> paramsIterator = params.iterator();
    for (TypeParameterMirror typeParam : typeParameters) {
        TypeParameter param = paramsIterator.next();
        List<TypeMirror> bounds = typeParam.getBounds();
        for (TypeMirror bound : bounds) {
            Type boundType;
            // we turn java's default upper bound java.lang.Object into ceylon.language.Object
            if (sameType(bound, OBJECT_TYPE)) {
                // especially since we do not want it for types
                if (bounds.size() == 1)
                    break;
                boundType = getNonPrimitiveType(getLanguageModule(), CEYLON_OBJECT_TYPE, scope);
            } else
                boundType = getNonPrimitiveType(ModelUtil.getModuleContainer(scope), bound, scope);
            param.getSatisfiedTypes().add(boundType);
        }
        if (needsObjectBounds && param.getSatisfiedTypes().isEmpty()) {
            Type boundType = getNonPrimitiveType(getLanguageModule(), CEYLON_OBJECT_TYPE, scope);
            param.getSatisfiedTypes().add(boundType);
        }
    }
}
Also used : LazyContainer(org.eclipse.ceylon.model.loader.model.LazyContainer) Function(org.eclipse.ceylon.model.typechecker.model.Function) LazyFunction(org.eclipse.ceylon.model.loader.model.LazyFunction) TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) TypeMirror(org.eclipse.ceylon.model.loader.mirror.TypeMirror) TypeParameterMirror(org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror)

Example 4 with TypeParameterMirror

use of org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror in project ceylon by eclipse.

the class AbstractModelLoader method applyTypeArguments.

private Type applyTypeArguments(Module moduleScope, TypeDeclaration declaration, TypeMirror type, Scope scope, TypeMappingMode mode, Set<TypeDeclaration> rawDeclarationsSeen) {
    List<TypeMirror> javacTypeArguments = type.getTypeArguments();
    boolean hasTypeParameters = declaration.isParameterized();
    boolean hasTypeArguments = !javacTypeArguments.isEmpty();
    boolean isRaw = !hasTypeArguments && hasTypeParameters;
    // if we have type arguments or type parameters (raw)
    if (hasTypeArguments || isRaw) {
        // if it's raw we will need the map anyways
        if (rawDeclarationsSeen == null)
            rawDeclarationsSeen = new HashSet<TypeDeclaration>();
        // detect recursive bounds that we can't possibly satisfy, such as Foo<T extends Foo<T>>
        if (rawDeclarationsSeen != null && !rawDeclarationsSeen.add(declaration))
            throw new RecursiveTypeParameterBoundException();
        try {
            List<Type> typeArguments = new ArrayList<Type>(javacTypeArguments.size());
            List<TypeParameter> typeParameters = declaration.getTypeParameters();
            List<TypeParameterMirror> typeParameterMirrors = null;
            // SimpleReflType for Object and friends don't have a type, but don't need one
            if (type.getDeclaredClass() != null)
                typeParameterMirrors = type.getDeclaredClass().getTypeParameters();
            Map<TypeParameter, SiteVariance> siteVarianceMap = null;
            int len = hasTypeArguments ? javacTypeArguments.size() : typeParameters.size();
            for (int i = 0; i < len; i++) {
                TypeParameter typeParameter = null;
                if (i < typeParameters.size())
                    typeParameter = typeParameters.get(i);
                Type producedTypeArgument = null;
                // do we have a type argument?
                TypeMirror typeArgument = null;
                SiteVariance siteVariance = null;
                if (hasTypeArguments) {
                    typeArgument = javacTypeArguments.get(i);
                    // if a single type argument is a wildcard and we are in a covariant location, we erase to Object
                    if (typeArgument.getKind() == TypeKind.WILDCARD) {
                        TypeMirror bound = typeArgument.getUpperBound();
                        if (bound != null) {
                            siteVariance = SiteVariance.OUT;
                        } else {
                            bound = typeArgument.getLowerBound();
                            if (bound != null) {
                                // it has a lower bound
                                siteVariance = SiteVariance.IN;
                            }
                        }
                        // use the bound in any case
                        typeArgument = bound;
                    }
                }
                // if we have no type argument, or if it's a wildcard with no bound, use the type parameter bounds if we can
                if (typeArgument == null && typeParameterMirrors != null && i < typeParameterMirrors.size()) {
                    TypeParameterMirror typeParameterMirror = typeParameterMirrors.get(i);
                    // FIXME: multiple bounds?
                    if (typeParameterMirror.getBounds().size() == 1) {
                        // make sure we don't go overboard
                        if (rawDeclarationsSeen == null) {
                            rawDeclarationsSeen = new HashSet<TypeDeclaration>();
                            // detect recursive bounds that we can't possibly satisfy, such as Foo<T extends Foo<T>>
                            if (!rawDeclarationsSeen.add(declaration))
                                throw new RecursiveTypeParameterBoundException();
                        }
                        TypeMirror bound = typeParameterMirror.getBounds().get(0);
                        try {
                            producedTypeArgument = obtainTypeParameterBound(moduleScope, bound, declaration, rawDeclarationsSeen);
                            siteVariance = SiteVariance.OUT;
                            // make sure we record that the type is not what it seems it is, so we can implement
                            // the method with proper raw type args and not substituted bounds
                            isRaw = true;
                        } catch (RecursiveTypeParameterBoundException x) {
                        // damnit, go for Object later
                        }
                    }
                }
                // let's fall back to "out Object"
                if (typeArgument == null && producedTypeArgument == null) {
                    producedTypeArgument = typeFactory.getObjectType();
                    siteVariance = SiteVariance.OUT;
                }
                // record use-site variance if required
                if (!ModelUtil.isCeylonDeclaration(declaration) && siteVariance != null) {
                    // lazy alloc
                    if (siteVarianceMap == null)
                        siteVarianceMap = new HashMap<TypeParameter, SiteVariance>();
                    siteVarianceMap.put(typeParameter, siteVariance);
                }
                // in some cases we may already have a produced type argument we can use. if not let's fetch it
                if (producedTypeArgument == null) {
                    if (mode == TypeMappingMode.NORMAL)
                        producedTypeArgument = obtainType(moduleScope, typeArgument, scope, TypeLocation.TYPE_PARAM);
                    else
                        producedTypeArgument = obtainTypeParameterBound(moduleScope, typeArgument, scope, rawDeclarationsSeen);
                }
                typeArguments.add(producedTypeArgument);
            }
            Type qualifyingType = null;
            if (type.getQualifyingType() != null) {
                qualifyingType = getNonPrimitiveType(moduleScope, type.getQualifyingType(), scope);
            }
            Type ret = declaration.appliedType(qualifyingType, typeArguments);
            if (siteVarianceMap != null) {
                ret.setVarianceOverrides(siteVarianceMap);
            }
            if (ret.isCached()) {
                ret = ret.clone();
            }
            ret.setUnderlyingType(type.getQualifiedName());
            ret.setRaw(isRaw);
            return ret;
        } finally {
            if (rawDeclarationsSeen != null)
                rawDeclarationsSeen.remove(declaration);
        }
    }
    // we have no type args, but perhaps we have a qualifying type which has some?
    if (type.getQualifyingType() != null) {
        // that one may have type arguments
        Type qualifyingType = getNonPrimitiveType(moduleScope, type.getQualifyingType(), scope);
        Type ret = declaration.appliedType(qualifyingType, Collections.<Type>emptyList());
        if (ret.isCached()) {
            ret = ret.clone();
        }
        ret.setUnderlyingType(type.getQualifiedName());
        ret.setRaw(isRaw);
        return ret;
    }
    // no type arg and no qualifying type
    return declaration.getType();
}
Also used : TypeParameter(org.eclipse.ceylon.model.typechecker.model.TypeParameter) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) SiteVariance(org.eclipse.ceylon.model.typechecker.model.SiteVariance) TypeMirror(org.eclipse.ceylon.model.loader.mirror.TypeMirror) TypeParameterMirror(org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration) HashSet(java.util.HashSet)

Example 5 with TypeParameterMirror

use of org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror in project ceylon by eclipse.

the class AbstractModelLoader method obtainTypeParameterBound.

private Type obtainTypeParameterBound(Module moduleScope, TypeMirror type, Scope scope, Set<TypeDeclaration> rawDeclarationsSeen) {
    // type variables are never mapped
    if (type.getKind() == TypeKind.TYPEVAR) {
        TypeParameterMirror typeParameter = type.getTypeParameter();
        if (!typeParameter.getBounds().isEmpty()) {
            List<Type> bounds = new ArrayList<Type>(typeParameter.getBounds().size());
            for (TypeMirror bound : typeParameter.getBounds()) {
                Type boundModel = obtainTypeParameterBound(moduleScope, bound, scope, rawDeclarationsSeen);
                bounds.add(boundModel);
            }
            return intersection(bounds, getUnitForModule(moduleScope));
        } else
            // no bound is Object
            return typeFactory.getObjectType();
    } else {
        TypeMirror mappedType = applyTypeMapping(type, TypeLocation.TYPE_PARAM);
        TypeDeclaration declaration = (TypeDeclaration) convertNonPrimitiveTypeToDeclaration(moduleScope, mappedType, scope, DeclarationType.TYPE);
        if (declaration == null) {
            throw new RuntimeException("Failed to find declaration for " + type);
        }
        if (declaration instanceof UnknownType)
            return declaration.getType();
        Type ret = applyTypeArguments(moduleScope, declaration, type, scope, TypeMappingMode.GENERATOR, rawDeclarationsSeen);
        if (ret.isCached()) {
            ret = ret.clone();
        }
        if (ret.getUnderlyingType() == null) {
            ret.setUnderlyingType(getUnderlyingType(type, TypeLocation.TYPE_PARAM));
        }
        return ret;
    }
}
Also used : UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) Type(org.eclipse.ceylon.model.typechecker.model.Type) UnknownType(org.eclipse.ceylon.model.typechecker.model.UnknownType) FunctionalInterfaceType(org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType) TypeMirror(org.eclipse.ceylon.model.loader.mirror.TypeMirror) TypeParameterMirror(org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror) ArrayList(java.util.ArrayList) TypeDeclaration(org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)

Aggregations

TypeParameterMirror (org.eclipse.ceylon.model.loader.mirror.TypeParameterMirror)6 ArrayList (java.util.ArrayList)5 FunctionalInterfaceType (org.eclipse.ceylon.model.loader.mirror.FunctionalInterfaceType)4 Type (org.eclipse.ceylon.model.typechecker.model.Type)4 UnknownType (org.eclipse.ceylon.model.typechecker.model.UnknownType)4 TypeMirror (org.eclipse.ceylon.model.loader.mirror.TypeMirror)3 TypeParameter (org.eclipse.ceylon.model.typechecker.model.TypeParameter)3 LazyContainer (org.eclipse.ceylon.model.loader.model.LazyContainer)2 TypeDeclaration (org.eclipse.ceylon.model.typechecker.model.TypeDeclaration)2 GenericArrayType (java.lang.reflect.GenericArrayType)1 ParameterizedType (java.lang.reflect.ParameterizedType)1 Type (java.lang.reflect.Type)1 TypeVariable (java.lang.reflect.TypeVariable)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1 CompletionFailure (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.CompletionFailure)1 TypeVariableSymbol (org.eclipse.ceylon.langtools.tools.javac.code.Symbol.TypeVariableSymbol)1