use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeArgumentInference method constrainInferredTypes.
private List<Type> constrainInferredTypes(List<TypeParameter> typeParameters, List<Type> inferredTypeArgs, Type qualifyingType, Declaration declaration) {
int size = inferredTypeArgs.size();
boolean found = false;
for (int i = 0; i < size; i++) {
TypeParameter tp = typeParameters.get(i);
// if (!tp.isCovariant()) {
List<Type> bounds = tp.getSatisfiedTypes();
if (!bounds.isEmpty()) {
found = true;
}
// }
}
if (found) {
Reference ref;
if (declaration instanceof Value) {
Value value = (Value) declaration;
if (value.getType().isTypeConstructor()) {
if (qualifyingType == null) {
ref = declaration.appliedReference(null, NO_TYPE_ARGS);
} else {
ref = qualifyingType.getTypedReference(declaration, NO_TYPE_ARGS);
}
TypeDeclaration dec = ref.getType().getDeclaration();
ref = dec.appliedReference(null, inferredTypeArgs);
} else {
return inferredTypeArgs;
}
} else {
if (qualifyingType == null) {
ref = declaration.appliedReference(null, inferredTypeArgs);
} else {
ref = qualifyingType.getTypedReference(declaration, inferredTypeArgs);
}
}
Map<TypeParameter, Type> args = ref.getTypeArguments();
ArrayList<Type> result = new ArrayList<Type>(size);
for (int i = 0; i < size; i++) {
TypeParameter tp = typeParameters.get(i);
Type arg = inferredTypeArgs.get(i);
Type constrainedArg = // tp.isCovariant() ? arg :
constrainInferredType(tp, arg, args);
result.add(constrainedArg);
}
return result;
} else {
return inferredTypeArgs;
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeVisitor method visit.
@Override
public void visit(Tree.SatisfiedTypes that) {
super.visit(that);
TypeDeclaration td = (TypeDeclaration) that.getScope();
if (td.isAlias()) {
return;
}
List<Tree.StaticType> types = that.getTypes();
List<Type> list = new ArrayList<Type>(types.size());
if (types.isEmpty()) {
that.addError("missing types in satisfies");
}
boolean foundTypeParam = false;
boolean foundClass = false;
boolean foundInterface = false;
for (Tree.StaticType st : types) {
inheritedType(st);
Type type = st.getTypeModel();
if (type != null) {
TypeDeclaration std = type.getDeclaration();
if (std != null && !(std instanceof UnknownType)) {
if (std == td) {
// unnecessary, handled by SupertypeVisitor
// st.addError("directly extends itself: '" +
// td.getName() + "'");
} else if (std instanceof NothingType) {
st.addError("satisfies the bottom type 'Nothing'");
} else if (std instanceof TypeAlias) {
st.addError("satisfies a type alias: '" + type.getDeclaration().getName(unit) + "'");
} else if (std instanceof Constructor) {
// nothing to do
} else if (td instanceof TypeParameter) {
if (foundTypeParam) {
st.addUnsupportedError("type parameter upper bounds are not yet supported in combination with other bounds");
} else if (std instanceof TypeParameter) {
if (foundClass || foundInterface) {
st.addUnsupportedError("type parameter upper bounds are not yet supported in combination with other bounds");
}
foundTypeParam = true;
list.add(type);
} else if (std instanceof Class) {
if (foundClass) {
st.addUnsupportedError("multiple class upper bounds are not yet supported");
}
foundClass = true;
list.add(type);
} else if (std instanceof Interface) {
foundInterface = true;
list.add(type);
} else {
st.addError("upper bound must be a class, interface, or type parameter");
}
} else {
if (std instanceof TypeParameter) {
st.addError("directly satisfies type parameter: '" + std.getName(unit) + "'");
} else if (std instanceof Class) {
st.addError("satisfies a class: '" + std.getName(unit) + "'");
} else if (std instanceof Interface) {
if (td.isDynamic() && !std.isDynamic()) {
st.addError("dynamic interface satisfies a non-dynamic interface: '" + std.getName(unit) + "'");
} else {
list.add(type);
}
} else {
st.addError("satisfied type must be an interface");
}
}
}
}
}
td.setSatisfiedTypes(list);
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeVisitor method visit.
@Override
public void visit(Tree.TypeParameterList that) {
super.visit(that);
List<Tree.TypeParameterDeclaration> tpds = that.getTypeParameterDeclarations();
List<TypeParameter> params = new ArrayList<TypeParameter>(tpds.size());
for (int i = tpds.size() - 1; i >= 0; i--) {
Tree.TypeParameterDeclaration tpd = tpds.get(i);
if (tpd != null) {
TypeParameter tp = tpd.getDeclarationModel();
Type dta = tp.getDefaultTypeArgument();
if (dta != null) {
params.add(tp);
if (dta.involvesTypeParameters(params)) {
tpd.getTypeSpecifier().addError("default type argument involves a type parameter not yet declared");
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeVisitor method visit.
/*@Override
public void visit(Tree.TypeConstraint that) {
super.visit(that);
if (that.getSelfType()!=null) {
TypeDeclaration td = (TypeDeclaration) that.getSelfType().getScope();
TypeParameter tp = that.getDeclarationModel();
td.setSelfType(tp.getType());
if (tp.isSelfType()) {
that.addError("type parameter may not act as self type for two different types");
}
else {
tp.setSelfTypedDeclaration(td);
}
}
}*/
@Override
public void visit(Tree.CaseTypes that) {
super.visit(that);
TypeDeclaration td = (TypeDeclaration) that.getScope();
List<Tree.StaticMemberOrTypeExpression> bmes = that.getBaseMemberExpressions();
List<Tree.StaticType> cts = that.getTypes();
List<TypedDeclaration> caseValues = new ArrayList<TypedDeclaration>(bmes.size());
List<Type> caseTypes = new ArrayList<Type>(bmes.size() + cts.size());
if (td instanceof TypeParameter) {
if (!bmes.isEmpty()) {
that.addError("cases of type parameter must be a types");
}
} else {
for (Tree.StaticMemberOrTypeExpression bme : bmes) {
// bmes have not yet been resolved
String name = name(bme.getIdentifier());
TypedDeclaration od = bme instanceof Tree.BaseMemberExpression ? getTypedDeclaration(bme.getScope(), name, null, false, unit) : getPackageTypedDeclaration(name, null, false, unit);
if (od != null) {
caseValues.add(od);
Type type = od.getType();
if (type != null) {
caseTypes.add(type);
}
}
}
}
for (Tree.StaticType ct : cts) {
inheritedType(ct);
Type type = ct.getTypeModel();
if (!isTypeUnknown(type)) {
if (type.isUnion() || type.isIntersection() || type.isNothing()) {
// union/intersection types don't have equals()
if (td instanceof TypeParameter) {
ct.addError("enumerated bound must be a class or interface type");
} else {
ct.addError("case type must be a class, interface, or self type");
}
} else {
TypeDeclaration ctd = type.getDeclaration();
if (ctd.equals(td)) {
ct.addError("directly enumerates itself: '" + td.getName() + "'");
} else if (type.isClassOrInterface()) {
caseTypes.add(type);
} else if (type.isTypeParameter()) {
if (td instanceof TypeParameter) {
caseTypes.add(type);
} else {
TypeParameter tp = (TypeParameter) ctd;
td.setSelfType(type);
if (tp.isSelfType()) {
ct.addError("type parameter may not act as self type for two different types");
} else {
tp.setSelfTypedDeclaration(td);
caseTypes.add(type);
}
if (cts.size() > 1) {
ct.addError("a type may not have more than one self type");
}
}
} else {
if (td instanceof TypeParameter) {
ct.addError("enumerated bound must be a class or interface type");
} else {
ct.addError("case type must be a class, interface, or self type");
}
}
}
}
}
if (!caseTypes.isEmpty()) {
TypeDeclaration first = caseTypes.get(0).getDeclaration();
if (caseTypes.size() == 1 && first.isSelfType()) {
// for a type family, the type that declares
// the type parameter may not be the same
// type for which it acts as a self type
Scope scope = first.getContainer();
if (scope instanceof ClassOrInterface) {
ClassOrInterface ci = (ClassOrInterface) scope;
if (!ci.isAbstract()) {
Tree.StaticType ct = cts.get(0);
if (ci.equals(td)) {
ct.addError("concrete class parameterized by self type: '" + ci.getName() + "' is not abstract but has the self type '" + first.getName() + "' (make '" + ci.getName() + "' abstract)", 905);
} else {
// type family
ct.addError("concrete class parameterized by self type: '" + ci.getName() + "' is not abstract but declares the self type '" + first.getName() + "' of '" + td.getName() + "' (make '" + ci.getName() + "' abstract)", 905);
}
}
}
} else {
if (td instanceof ClassOrInterface) {
ClassOrInterface ci = (ClassOrInterface) td;
if (!ci.isAbstract()) {
Class c = (Class) ci;
if (!c.hasEnumerated()) {
that.addError("concrete class has enumerated subtypes: " + "enumerated class '" + ci.getName() + "' is not abstract" + " (make '" + ci.getName() + "' abstract)", 905);
}
}
}
}
td.setCaseTypes(caseTypes);
td.setCaseValues(caseValues);
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeParameter in project ceylon by eclipse.
the class TypeVisitor method visitSimpleType.
private void visitSimpleType(Tree.SimpleType that, Type ot, TypeDeclaration dec) {
if (dec instanceof Constructor && // is allowed
!inTypeLiteral && // constructor is allowed
!inExtendsOrClassAlias && !inDelegatedConstructor) {
that.addError("constructor is not a type: '" + dec.getName(unit) + "' is a constructor");
}
Tree.TypeArgumentList tal = that.getTypeArgumentList();
if (tal != null) {
dec = unwrapAliasedTypeConstructor(dec);
}
List<TypeParameter> params = dec.getTypeParameters();
List<Type> typeArgs = getTypeArguments(tal, ot, params);
// Note: we actually *check* these type arguments
// later in ExpressionVisitor
Type pt = dec.appliedType(ot, typeArgs);
if (tal == null) {
if (!params.isEmpty()) {
// For now the only type constructors allowed
// as the type of a value are type constructors
// that alias Callable (in future relax this)
// and interpret *every* type with a missing
// type argument list as a type constructor
Interface cd = unit.getCallableDeclaration();
boolean functionTypeConstructor = dec.isAlias() ? dec.inherits(cd) : dec.equals(cd);
if (functionTypeConstructor) {
pt.setTypeConstructor(true);
}
}
} else {
if (params.isEmpty()) {
that.addError("type declaration does not accept type arguments: '" + dec.getName(unit) + "' is not a generic type");
}
tal.setTypeModels(typeArgs);
List<Tree.Type> args = tal.getTypes();
for (int i = 0; i < args.size() && i < params.size(); i++) {
Tree.Type t = args.get(i);
if (t instanceof Tree.StaticType) {
Tree.StaticType st = (Tree.StaticType) t;
Tree.TypeVariance variance = st.getTypeVariance();
if (variance != null) {
TypeParameter p = params.get(i);
String var = variance.getText();
if (var.equals("out")) {
pt.setVariance(p, OUT);
} else if (var.equals("in")) {
pt.setVariance(p, IN);
}
if (!p.isInvariant()) {
// Type doesn't yet know
// how to reason about *runtime*
// instantiations of variant types
// since they are effectively
// invariant
variance.addUnsupportedError("use-site variant instantiation of declaration-site variant types is not supported: type parameter '" + p.getName() + "' of '" + dec.getName(unit) + "' is declared " + (p.isCovariant() ? "covariant" : "contravariant") + " (remove the '" + var + "')");
}
}
}
}
}
that.setTypeModel(pt);
that.setDeclarationModel(dec);
}
Aggregations