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);
}
}
}
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);
}
}
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);
}
}
}
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();
}
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;
}
}
Aggregations