use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class JsonPackage method getTypeFromJson.
/**
* Looks up a type from model data, creating it if necessary. The returned type will have its
* type parameters substituted if needed.
*/
private Type getTypeFromJson(Map<String, Object> m, Declaration container, List<TypeParameter> typeParams) {
TypeDeclaration td = null;
if (m.get(KEY_METATYPE) instanceof TypeDeclaration) {
td = (TypeDeclaration) m.get(KEY_METATYPE);
if (td instanceof ClassOrInterface && td.getUnit().getPackage() instanceof JsonPackage) {
((JsonPackage) td.getUnit().getPackage()).load(td.getName(), typeParams);
}
}
final String tname = (String) m.get(KEY_NAME);
if ("$U".equals(tname)) {
m.put(KEY_METATYPE, unknown);
return unknown.getType();
}
if (td == null && m.containsKey("comp")) {
@SuppressWarnings("unchecked") final List<Map<String, Object>> tmaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
final ArrayList<Type> types = new ArrayList<>(tmaps.size());
if ("u".equals(m.get("comp"))) {
UnionType ut = new UnionType(u2);
for (Map<String, Object> tmap : tmaps) {
types.add(getTypeFromJson(tmap, container, typeParams));
}
ut.setCaseTypes(types);
td = ut;
} else if ("i".equals(m.get("comp"))) {
IntersectionType it = new IntersectionType(u2);
for (Map<String, Object> tmap : tmaps) {
types.add(getTypeFromJson(tmap, container, typeParams));
}
it.setSatisfiedTypes(types);
td = it;
} else {
throw new IllegalArgumentException("Invalid composite type '" + m.get("comp") + "'");
}
} else if (td == null) {
final String pname = (String) m.get(KEY_PACKAGE);
if (pname == null) {
// It's a ref to a type parameter
final List<TypeParameter> containerTypeParameters;
if (container instanceof Constructor) {
containerTypeParameters = ((Generic) container.getContainer()).getTypeParameters();
} else if (container instanceof Generic) {
containerTypeParameters = container.getTypeParameters();
} else {
containerTypeParameters = null;
}
if (containerTypeParameters != null) {
for (TypeParameter typeParam : containerTypeParameters) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
if (td == null && typeParams != null) {
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(tname)) {
td = typeParam;
}
}
}
} else {
String mname = (String) m.get(KEY_MODULE);
if ("$".equals(mname)) {
mname = LANGUAGE_MODULE_NAME;
}
org.eclipse.ceylon.model.typechecker.model.Package rp;
if ("$".equals(pname) || LANGUAGE_MODULE_NAME.equals(pname)) {
// Language module package
rp = isLanguagePackage() ? this : getModule().getLanguageModule().getDirectPackage(LANGUAGE_MODULE_NAME);
} else if (mname == null) {
// local type
if (".".equals(pname)) {
rp = this;
if (container instanceof TypeDeclaration && tname.equals(container.getName())) {
td = (TypeDeclaration) container;
}
} else {
rp = getModule().getDirectPackage(pname);
}
} else {
rp = getModule().getPackage(pname);
}
if (rp == null) {
throw new CompilerErrorException("Package not found: " + pname);
}
if (rp != this && rp instanceof JsonPackage && !((JsonPackage) rp).loaded) {
((JsonPackage) rp).loadIfNecessary();
}
final boolean nested = tname.indexOf('.') > 0;
final String level1 = nested ? tname.substring(0, tname.indexOf('.')) : tname;
if (rp != null && !nested) {
Declaration d = rp.getDirectMember(tname, null, false);
if (d instanceof TypeDeclaration) {
td = (TypeDeclaration) d;
if (td.isTuple()) {
if (m.containsKey(KEY_TYPES)) {
@SuppressWarnings("unchecked") List<Map<String, Object>> elemaps = (List<Map<String, Object>>) m.get(KEY_TYPES);
ArrayList<Type> elems = new ArrayList<>(elemaps.size());
for (Map<String, Object> elem : elemaps) {
elems.add(getTypeFromJson(elem, container, typeParams));
}
Type tail = elems.get(elems.size() - 1);
if ((tail.isSequence() || tail.isSequential()) && !tail.isTuple() && !tail.isEmpty()) {
elems.remove(elems.size() - 1);
} else {
tail = null;
}
return u2.getTupleType(elems, tail, -1);
} else if (m.containsKey("count")) {
@SuppressWarnings("unchecked") Map<String, Object> elem = (Map<String, Object>) m.get(KEY_TYPE);
Type[] elems = new Type[(int) m.remove("count")];
Arrays.fill(elems, getTypeFromJson(elem, container, typeParams));
return u2.getTupleType(Arrays.asList(elems), null, -1);
}
}
} else if (d instanceof FunctionOrValue) {
td = ((FunctionOrValue) d).getTypeDeclaration();
}
}
if (td == null && rp instanceof JsonPackage) {
if (nested) {
td = ((JsonPackage) rp).loadNestedType(tname, typeParams);
} else {
td = (TypeDeclaration) ((JsonPackage) rp).load(tname, typeParams);
}
}
// Then look in the top-level declarations
if (nested && td == null) {
for (Declaration d : rp.getMembers()) {
if (d instanceof TypeDeclaration && level1.equals(d.getName())) {
td = (TypeDeclaration) d;
}
}
final String[] path = tname.split("\\.");
for (int i = 1; i < path.length; i++) {
td = (TypeDeclaration) td.getDirectMember(path[i], null, false);
}
}
}
}
// From 1.2.3 we stored type arguments in maps
final Type newType = loadTypeArguments(m, td, container, typeParams);
if (newType != null) {
return newType;
}
// This is the old pre 1.2.3 stuff
@SuppressWarnings("unchecked") final List<Map<String, Object>> modelParms = (List<Map<String, Object>>) m.get(KEY_TYPE_PARAMS);
if (td != null && modelParms != null) {
// Substitute type parameters
final HashMap<TypeParameter, Type> concretes = new HashMap<>();
HashMap<TypeParameter, SiteVariance> variances = null;
if (td.getTypeParameters().size() < modelParms.size()) {
if (td.getUnit().getPackage() == this) {
parseTypeParameters(modelParms, td, null);
}
}
final Iterator<TypeParameter> viter = td.getTypeParameters().iterator();
for (Map<String, Object> ptparm : modelParms) {
TypeParameter _cparm = viter.next();
if (ptparm.containsKey(KEY_PACKAGE) || ptparm.containsKey(KEY_TYPES)) {
// Substitute for proper type
final Type _pt = getTypeFromJson(ptparm, container, typeParams);
concretes.put(_cparm, _pt);
} else if (ptparm.containsKey(KEY_NAME) && typeParams != null) {
// Look for type parameter with same name
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(ptparm.get(KEY_NAME))) {
concretes.put(_cparm, typeParam.getType());
}
}
}
Integer usv = (Integer) ptparm.get(KEY_US_VARIANCE);
if (usv != null) {
if (variances == null) {
variances = new HashMap<>();
}
variances.put(_cparm, SiteVariance.values()[usv]);
}
}
if (!concretes.isEmpty()) {
return td.getType().substitute(concretes, variances);
}
}
if (td == null) {
try {
throw new IllegalArgumentException(String.format("Couldn't find type %s::%s for %s in %s<%s> (FROM pkg %s)", m.get(KEY_PACKAGE), m.get(KEY_NAME), m.get(KEY_MODULE), m, typeParams, getNameAsString()));
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
return td.getType();
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class Metamodel method getTypeArgumentWithVariances.
public static ceylon.language.Map<? extends ceylon.language.meta.declaration.TypeParameter, ? extends ceylon.language.Sequence<? extends Object>> getTypeArgumentWithVariances(ceylon.language.meta.declaration.GenericDeclaration declaration, Reference appliedFunction) {
java.util.Map<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<? extends Object>> typeArguments = new LinkedHashMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<? extends Object>>();
Iterator<? extends ceylon.language.meta.declaration.TypeParameter> typeParameters = declaration.getTypeParameterDeclarations().iterator();
Object it;
java.util.Map<org.eclipse.ceylon.model.typechecker.model.TypeParameter, org.eclipse.ceylon.model.typechecker.model.Type> ptArguments = appliedFunction.getTypeArguments();
Map<TypeParameter, SiteVariance> varianceOverrides = appliedFunction instanceof org.eclipse.ceylon.model.typechecker.model.Type ? ((org.eclipse.ceylon.model.typechecker.model.Type) appliedFunction).getVarianceOverrides() : null;
while ((it = typeParameters.next()) != finished_.get_()) {
org.eclipse.ceylon.compiler.java.runtime.metamodel.decl.TypeParameterImpl tp = (org.eclipse.ceylon.compiler.java.runtime.metamodel.decl.TypeParameterImpl) it;
org.eclipse.ceylon.model.typechecker.model.TypeParameter tpDecl = (org.eclipse.ceylon.model.typechecker.model.TypeParameter) tp.declaration;
org.eclipse.ceylon.model.typechecker.model.Type ptArg = ptArguments.get(tpDecl);
ceylon.language.meta.model.Type<?> ptArgWrapped = Metamodel.getAppliedMetamodel(ptArg);
ceylon.language.meta.declaration.Variance variance = modelVarianceToMetaModel(varianceOverrides, tpDecl);
ceylon.language.Sequence<? extends Object> tuple = ceylon.language.Tuple.instance(TD_ClosedTypeArgumentElement, new Object[] { ptArgWrapped, variance });
typeArguments.put(tp, tuple);
}
return new InternalMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<?>>(ceylon.language.meta.declaration.TypeParameter.$TypeDescriptor$, TD_ClosedTypeArgument, typeArguments);
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class OpenClassOrInterfaceTypeImpl method init.
protected void init() {
org.eclipse.ceylon.model.typechecker.model.ClassOrInterface decl = (org.eclipse.ceylon.model.typechecker.model.ClassOrInterface) producedType.getDeclaration();
this.declaration = (ClassOrInterfaceDeclarationImpl) Metamodel.getOrCreateMetamodel(decl);
java.util.Map<ceylon.language.meta.declaration.TypeParameter, ceylon.language.meta.declaration.OpenType> typeArguments = new LinkedHashMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.meta.declaration.OpenType>();
java.util.Map<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<? extends Object>> typeArgumentWithVariances = new LinkedHashMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<? extends Object>>();
Iterator<? extends ceylon.language.meta.declaration.TypeParameter> typeParameters = declaration.getTypeParameterDeclarations().iterator();
Object it;
java.util.Map<org.eclipse.ceylon.model.typechecker.model.TypeParameter, org.eclipse.ceylon.model.typechecker.model.Type> ptArguments = producedType.getTypeArguments();
java.util.Map<TypeParameter, SiteVariance> varianceOverrides = producedType.getVarianceOverrides();
while ((it = typeParameters.next()) != finished_.get_()) {
org.eclipse.ceylon.compiler.java.runtime.metamodel.decl.TypeParameterImpl tp = (org.eclipse.ceylon.compiler.java.runtime.metamodel.decl.TypeParameterImpl) it;
org.eclipse.ceylon.model.typechecker.model.TypeParameter tpDecl = (org.eclipse.ceylon.model.typechecker.model.TypeParameter) tp.declaration;
org.eclipse.ceylon.model.typechecker.model.Type ptArg = ptArguments.get(tpDecl);
OpenType ptArgWrapped = Metamodel.getMetamodel(ptArg);
typeArguments.put(tp, ptArgWrapped);
ceylon.language.meta.declaration.Variance variance = Metamodel.modelVarianceToMetaModel(varianceOverrides, tpDecl);
ceylon.language.Sequence<? extends Object> tuple = ceylon.language.Tuple.instance(Metamodel.TD_OpenTypeArgumentElement, new Object[] { ptArgWrapped, variance });
typeArgumentWithVariances.put(tp, tuple);
}
this.typeArguments = new InternalMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.meta.declaration.OpenType>(ceylon.language.meta.declaration.TypeParameter.$TypeDescriptor$, ceylon.language.meta.declaration.OpenType.$TypeDescriptor$, typeArguments);
this.typeArgumentWithVariances = new InternalMap<ceylon.language.meta.declaration.TypeParameter, ceylon.language.Sequence<?>>(ceylon.language.meta.declaration.TypeParameter.$TypeDescriptor$, Metamodel.TD_OpenTypeArgument, typeArgumentWithVariances);
org.eclipse.ceylon.model.typechecker.model.Type superType = decl.getExtendedType();
if (superType != null) {
org.eclipse.ceylon.model.typechecker.model.Type superTypeResolved = superType.substitute(producedType);
this.superclass = (ceylon.language.meta.declaration.OpenClassType) Metamodel.getMetamodel(superTypeResolved);
}
List<org.eclipse.ceylon.model.typechecker.model.Type> satisfiedTypes = decl.getSatisfiedTypes();
ceylon.language.meta.declaration.OpenInterfaceType[] interfaces = new ceylon.language.meta.declaration.OpenInterfaceType[satisfiedTypes.size()];
int i = 0;
for (org.eclipse.ceylon.model.typechecker.model.Type pt : satisfiedTypes) {
org.eclipse.ceylon.model.typechecker.model.Type resolvedPt = pt.substitute(producedType);
interfaces[i++] = (ceylon.language.meta.declaration.OpenInterfaceType) Metamodel.getMetamodel(resolvedPt);
}
this.interfaces = Util.sequentialWrapper(ceylon.language.meta.declaration.OpenInterfaceType.$TypeDescriptor$, interfaces);
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance 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.typechecker.model.SiteVariance in project ceylon by eclipse.
the class TypeParser method loadType.
private Type loadType(String pkg, String fullName, Part part, Type qualifyingType) {
// try to find a qualified type
try {
Declaration newDeclaration;
if (qualifyingType == null) {
// FIXME: this only works for packages not contained in multiple modules
Package foundPackage = moduleScope.getPackage(pkg);
if (foundPackage != null)
newDeclaration = loader.getDeclaration(foundPackage.getModule(), pkg, fullName, scope);
else if (scope != null && !pkg.isEmpty() && loader.isDynamicMetamodel()) {
// try the default module, damnit
newDeclaration = loader.getDeclaration(loader.getLoadedModule(Module.DEFAULT_MODULE_NAME, null), pkg, fullName, scope);
} else if (scope != null) {
// if we did not find any package and the scope is null, chances are we're after a type variable
// or a relative type, so use the module scope
newDeclaration = loader.getDeclaration(moduleScope, pkg, fullName, scope);
} else
newDeclaration = null;
} else {
// look it up via its qualifying type or decl
Declaration qualifyingDeclaration = qualifyingType.getDeclaration();
if (qualifyingType.isUnion() || qualifyingType.isIntersection()) {
newDeclaration = qualifyingDeclaration.getMember(part.name, null, false);
} else {
if (qualifyingDeclaration instanceof FunctionOrValueInterface)
qualifyingDeclaration = ((FunctionOrValueInterface) qualifyingDeclaration).getUnderlyingDeclaration();
newDeclaration = AbstractModelLoader.getDirectMember((Scope) qualifyingDeclaration, part.name);
}
if (newDeclaration == null)
throw new ModelResolutionException("Failed to resolve inner type or declaration " + part.name + " in " + qualifyingDeclaration.getQualifiedNameString());
}
if (newDeclaration == null)
return null;
TypeDeclaration newTypeDeclaration;
if (newDeclaration instanceof TypeDeclaration)
newTypeDeclaration = (TypeDeclaration) newDeclaration;
else
newTypeDeclaration = new FunctionOrValueInterface((TypedDeclaration) newDeclaration);
Type ret = newTypeDeclaration.appliedType(qualifyingType, part.getParameters());
// set the use-site variance if required, now that we know the TypeParameter declarations
if (!part.getVariance().isEmpty()) {
List<TypeParameter> tps = newTypeDeclaration.getTypeParameters();
List<SiteVariance> variance = part.getVariance();
for (int i = 0, l1 = tps.size(), l2 = variance.size(); i < l1 && i < l2; i++) {
SiteVariance siteVariance = variance.get(i);
if (siteVariance != null) {
ret.setVariance(tps.get(i), siteVariance);
}
}
}
return ret;
} catch (ModelResolutionException x) {
// - if we have type parameters we must have a type
if (qualifyingType != null || (part.parameters != null && !part.parameters.isEmpty()))
throw x;
return null;
}
}
Aggregations