use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class TypeParserTests method testParamsVariance2.
@Test
public void testParamsVariance2() {
Type type = new TypeParser(MockLoader.instance).decodeType("t2<b,out c>", null, mockDefaultModule, mockPkgUnit);
assertTypeWithParameters(type);
Map<TypeParameter, SiteVariance> varianceOverrides = type.getVarianceOverrides();
Assert.assertNotNull(varianceOverrides);
Assert.assertEquals(1, varianceOverrides.size());
List<TypeParameter> tps = type.getDeclaration().getTypeParameters();
Assert.assertEquals(null, varianceOverrides.get(tps.get(0)));
Assert.assertEquals(SiteVariance.OUT, varianceOverrides.get(tps.get(1)));
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class TypeParser method parseTypeArgumentVariance.
/**
* Spec says:
* <blockquote><pre>
* Variance: ("out" | "in")?
* </blockquote></pre>
* Which is what we do, but by updating the given part.
*/
private void parseTypeArgumentVariance(Part type) {
SiteVariance variance = null;
if (lexer.lookingAt(TypeLexer.OUT)) {
variance = SiteVariance.OUT;
lexer.eat();
} else if (lexer.lookingAt(TypeLexer.IN)) {
variance = SiteVariance.IN;
lexer.eat();
}
// lazy allocation
if (variance != null && type.variance == null) {
type.variance = new LinkedList<SiteVariance>();
for (int i = 0, l = type.getParameters().size(); i < l; i++) {
// patch it up for the previous type params which did not have variance
type.variance.add(null);
}
}
// only add the variance if we have to
if (type.variance != null) {
// we add it even if it's null, as long as we're recording variance
type.variance.add(variance);
}
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class ExpressionVisitor method checkArgumentsAgainstTypeConstructor.
private void checkArgumentsAgainstTypeConstructor(List<Type> typeArguments, Tree.TypeArguments tas, Type type, Node parent) {
boolean explicit = tas instanceof Tree.TypeArgumentList;
TypeDeclaration tcd = type.getDeclaration();
List<TypeParameter> typeParameters = tcd.getTypeParameters();
int size = typeArguments.size();
if (size != typeParameters.size()) {
tas.addError("wrong number of type arguments: type constructor requires " + size + " type arguments");
} else {
Map<TypeParameter, Type> args = getTypeArgumentMap(tcd, null, typeArguments);
Map<TypeParameter, SiteVariance> variances = // TODO!!!!!
Collections.emptyMap();
for (int i = 0; i < size; i++) {
TypeParameter param = typeParameters.get(i);
Type arg = typeArguments.get(i);
if (!isTypeUnknown(arg)) {
List<Type> sts = param.getSatisfiedTypes();
for (Type st : sts) {
Type bound = st.substitute(args, variances);
if (!isTypeUnknown(bound) && !arg.isSubtypeOf(bound)) {
String message = "type argument '" + arg.asString(unit) + "' is not assignable to upper bound '" + bound.asString(unit) + "' of type parameter '" + param.getName() + "' of '" + param.getDeclaration().getName(unit) + "'";
if (explicit) {
typeArgNode(tas, i, parent).addError(message);
} else {
parent.addError("inferred " + message);
}
}
}
}
if (!satisfiesEnumeratedConstraint(param, arg, args, variances)) {
String message = "type argument '" + arg.asString(unit) + "' is not one of the enumerated cases of the type parameter '" + param.getName() + "' of '" + param.getDeclaration().getName(unit) + "'";
if (explicit) {
typeArgNode(tas, i, parent).addError(message);
} else {
parent.addError("inferred " + message);
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class AnalyzerUtil method getTypeArguments.
/**
* Get the type arguments specified explicitly in the
* code, or an empty list if no type arguments were
* explicitly specified. For missing arguments, use
* default type arguments.
*
* @param tas the type argument list
* @param qualifyingType the qualifying type
* @param typeParameters the list of type parameters
*
* @return a list of type arguments to the given type
* parameters
*/
static List<Type> getTypeArguments(Tree.TypeArguments tas, Type qualifyingType, List<TypeParameter> typeParameters) {
if (tas instanceof Tree.TypeArgumentList) {
// accumulate substitutions in case we need
// them below for calculating default args
Map<TypeParameter, Type> typeArgs = new HashMap<TypeParameter, Type>();
Map<TypeParameter, SiteVariance> vars = new HashMap<TypeParameter, SiteVariance>();
if (qualifyingType != null) {
typeArgs.putAll(qualifyingType.getTypeArguments());
vars.putAll(qualifyingType.getVarianceOverrides());
}
Tree.TypeArgumentList tal = (Tree.TypeArgumentList) tas;
int size = typeParameters.size();
List<Type> typeArguments = new ArrayList<Type>(size);
List<Tree.Type> types = tal.getTypes();
int count = types.size();
for (int i = 0; i < count; i++) {
Tree.Type type = types.get(i);
Type t = type.getTypeModel();
if (t == null) {
typeArguments.add(null);
} else {
typeArguments.add(t);
if (i < size) {
TypeParameter tp = typeParameters.get(i);
if (tp.isTypeConstructor()) {
setTypeConstructor(type, tp);
}
typeArgs.put(tp, t);
if (type instanceof Tree.StaticType) {
Tree.StaticType st = (Tree.StaticType) type;
TypeVariance tv = st.getTypeVariance();
if (tv != null) {
boolean contra = tv.getText().equals("in");
vars.put(tp, contra ? IN : OUT);
}
}
}
}
}
// for missing arguments, use the default args
for (int i = typeArguments.size(); i < size; i++) {
TypeParameter tp = typeParameters.get(i);
Type dta = tp.getDefaultTypeArgument();
if (dta == null) {
break;
} else {
Type da = dta.substitute(typeArgs, vars);
typeArguments.add(da);
typeArgs.put(tp, da);
}
}
return typeArguments;
} else if (tas instanceof Tree.InferredTypeArguments && tas.getTypeModels() != null) {
return tas.getTypeModels();
} else {
return emptyList();
}
}
use of org.eclipse.ceylon.model.typechecker.model.SiteVariance in project ceylon by eclipse.
the class JsonPackage method loadTypeArguments.
/**
* Load the type arguments from a map where keys are the type argument names (including their types,
* e.g. List.Element) and the keys are maps suitable for decoding with getTypeFromJson)
*/
Type loadTypeArguments(Map<String, Object> m, final TypeDeclaration td, final Declaration container, final List<TypeParameter> typeParams) {
if (td == null) {
return null;
}
@SuppressWarnings("unchecked") final Map<String, Map<String, Object>> targs = (Map<String, Map<String, Object>>) m.get(KEY_TYPE_ARGS);
if (targs == null) {
return null;
}
// Substitute type parameters
final HashMap<TypeParameter, Type> concretes = new HashMap<>(targs.size());
HashMap<TypeParameter, SiteVariance> variances = null;
Declaration d = td;
while (d != null) {
for (TypeParameter tparm : d.getTypeParameters()) {
Map<String, Object> targMap = targs.get(partiallyQualifiedName(d) + "." + tparm.getName());
if (targMap == null) {
// TODO error I guess
continue;
}
if (targMap.containsKey(KEY_PACKAGE) || targMap.containsKey(KEY_TYPES)) {
// Substitute for proper type
final Type _pt = getTypeFromJson(targMap, container, typeParams);
concretes.put(tparm, _pt);
} else if (targMap.containsKey(KEY_NAME) && typeParams != null) {
// Look for type parameter with same name
for (TypeParameter typeParam : typeParams) {
if (typeParam.getName().equals(targMap.get(KEY_NAME))) {
concretes.put(tparm, typeParam.getType());
}
}
}
Integer usv = (Integer) targMap.get(KEY_US_VARIANCE);
if (usv != null) {
if (variances == null) {
variances = new HashMap<>();
}
variances.put(tparm, SiteVariance.values()[usv]);
}
}
d = ModelUtil.getContainingDeclaration(d);
}
if (!concretes.isEmpty()) {
return td.getType().substitute(concretes, variances);
}
return null;
}
Aggregations