use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class InheritanceVisitor method visit.
@Override
public void visit(Tree.ExtendedType that) {
super.visit(that);
TypeDeclaration td = (TypeDeclaration) that.getScope();
if (!td.isAlias()) {
Tree.SimpleType et = that.getType();
if (et != null) {
Tree.InvocationExpression ie = that.getInvocationExpression();
Class clazz = (Class) td;
boolean hasConstructors = clazz.hasConstructors() || clazz.hasEnumerated();
boolean anonymous = clazz.isAnonymous();
if (ie == null) {
if (!hasConstructors || anonymous) {
et.addError("missing instantiation arguments");
}
} else {
if (hasConstructors && !anonymous) {
et.addError("unnecessary instantiation arguments");
}
}
Unit unit = that.getUnit();
Type type = et.getTypeModel();
if (type != null) {
checkSelfTypes(et, td, type);
checkExtensionOfMemberType(et, td, type);
// checkCaseOfSupertype(et, td, type);
Type ext = td.getExtendedType();
TypeDeclaration etd = ext == null ? null : ext.getDeclaration();
TypeDeclaration aetd = type.getDeclaration();
if (aetd instanceof Constructor && aetd.isAbstract()) {
et.addError("extends a partial constructor: '" + aetd.getName(unit) + "' is declared abstract");
}
while (etd != null && etd.isAlias()) {
Type etdet = etd.getExtendedType();
etd = etdet == null ? null : etdet.getDeclaration();
}
if (etd != null) {
if (etd.isFinal()) {
et.addError("extends a final class: '" + etd.getName(unit) + "' is declared final");
}
if (aetd instanceof Class && !contains(aetd, that.getScope())) {
Class c = (Class) aetd;
Constructor dc = c.getDefaultConstructor();
if (dc != null && !dc.isShared()) {
that.addError("extends a class with an unshared default constructor: default constructor of '" + c.getName(unit) + "' is not 'shared'");
}
}
if (etd.isSealed() && !unit.inSameModule(etd)) {
String moduleName = etd.getUnit().getPackage().getModule().getNameAsString();
et.addError("extends a sealed class in a different module: '" + etd.getName(unit) + "' in '" + moduleName + "' is sealed");
}
}
}
checkSupertypeVarianceAnnotations(et);
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class TypeArgumentInference method inferTypeArg.
private Type inferTypeArg(TypeParameter tp, Type paramType, Type argType, boolean covariant, boolean contravariant, boolean findingUpperBounds, List<TypeParameter> visited, Node argNode) {
if (paramType != null && argType != null) {
paramType = paramType.resolveAliases();
argType = argType.resolveAliases();
TypeDeclaration paramTypeDec = paramType.getDeclaration();
Map<TypeParameter, Type> paramTypeArgs = paramType.getTypeArguments();
Map<TypeParameter, SiteVariance> paramVariances = paramType.getVarianceOverrides();
if (paramType.isTypeParameter() && paramTypeDec.equals(tp)) {
if (tp.isTypeConstructor()) {
if (argType.isTypeConstructor()) {
return argType;
} else {
return null;
}
} else if (findingUpperBounds && covariant || !findingUpperBounds && contravariant) {
// covariant locations in the list
return null;
} else if (argType.isUnknown()) {
// TODO: is this error really necessary now!?
if (!argNode.hasErrors()) {
argNode.addError("argument of unknown type assigned to inferred type parameter: '" + tp.getName() + "' of '" + tp.getDeclaration().getName(unit) + "'");
}
// TODO: would it be better to return UnknownType here?
return null;
} else {
return unit.denotableType(argType);
}
} else if (paramType.isTypeParameter() && !paramTypeDec.isParameterized()) {
TypeParameter tp2 = (TypeParameter) paramTypeDec;
if (!findingUpperBounds && // in the upper bounds
!visited.contains(tp2)) {
visited.add(tp2);
List<Type> sts = tp2.getSatisfiedTypes();
List<Type> list = new ArrayList<Type>(sts.size());
for (Type upperBound : sts) {
// recurse to the upper bounds
addToUnionOrIntersection(findingUpperBounds, list, inferTypeArg(tp, upperBound, argType, covariant, contravariant, findingUpperBounds, visited, argNode));
}
visited.remove(tp2);
return unionOrIntersectionOrNull(findingUpperBounds, list);
} else {
return null;
}
} else if (paramType.isUnion()) {
// If there is more than one type parameter in
// the union, ignore this union when inferring
// types.
// TODO: This is all a bit adhoc. The problem
// is that when a parameter type involves
// a union of type parameters, it in theory
// imposes a compound constraint upon the
// type parameters, but our algorithm
// doesn't know how to deal with compound
// constraints
/*Type typeParamType = null;
boolean found = false;
for (Type ct:
paramType.getDeclaration()
.getCaseTypes()) {
TypeDeclaration ctd =
ct.getDeclaration();
if (ctd instanceof TypeParameter) {
typeParamType = ct;
}
if (ct.containsTypeParameters()) { //TODO: check that they are "free" type params
if (found) {
//the parameter type involves two type
//parameters which are being inferred
return null;
}
else {
found = true;
}
}
}*/
Type pt = paramType;
Type apt = argType;
if (argType.isUnion()) {
for (Type act : argType.getCaseTypes()) {
// from both unions
if (// in a recursive generic function, T can get assigned to T
!act.involvesDeclaration(tp) && act.substitute(argType).isSubtypeOf(paramType)) {
pt = pt.shallowMinus(act);
apt = apt.shallowMinus(act);
}
}
}
if (pt.isUnion()) {
boolean found = false;
for (Type ct : pt.getCaseTypes()) {
if (ct.isTypeParameter()) {
if (found) {
return null;
}
found = true;
}
}
// just one type parameter left in the union
Map<TypeParameter, Type> args = pt.getTypeArguments();
Map<TypeParameter, SiteVariance> variances = pt.getVarianceOverrides();
List<Type> cts = pt.getCaseTypes();
List<Type> list = new ArrayList<Type>(cts.size());
for (Type ct : cts) {
addToUnionOrIntersection(findingUpperBounds, list, inferTypeArg(tp, ct.substitute(args, variances), apt, covariant, contravariant, findingUpperBounds, visited, argNode));
}
return unionOrIntersectionOrNull(findingUpperBounds, list);
} else {
return inferTypeArg(tp, pt, apt, covariant, contravariant, findingUpperBounds, visited, argNode);
}
/*else {
//if the param type is of form T|A1 and the arg type is
//of form A2|B then constrain T by B and A1 by A2
Type pt = paramType.minus(typeParamType);
addToUnionOrIntersection(tp, list, inferTypeArg(tp,
paramType.minus(pt), argType.minus(pt), visited));
addToUnionOrIntersection(tp, list, inferTypeArg(tp,
paramType.minus(typeParamType), pt, visited));
//return null;
}*/
} else if (paramType.isIntersection()) {
List<Type> sts = paramTypeDec.getSatisfiedTypes();
List<Type> list = new ArrayList<Type>(sts.size());
for (Type ct : sts) {
// recurse to intersected types
addToUnionOrIntersection(findingUpperBounds, list, inferTypeArg(tp, ct.substitute(paramTypeArgs, paramVariances), argType, covariant, contravariant, findingUpperBounds, visited, argNode));
}
return unionOrIntersectionOrNull(findingUpperBounds, list);
} else if (argType.isUnion()) {
List<Type> cts = argType.getCaseTypes();
List<Type> list = new ArrayList<Type>(cts.size());
for (Type ct : cts) {
// recurse to union types
addToUnion(list, inferTypeArg(tp, paramType, ct.substitute(paramTypeArgs, paramVariances), covariant, contravariant, findingUpperBounds, visited, argNode));
}
return unionOrNull(list);
} else if (argType.isIntersection()) {
List<Type> sts = argType.getSatisfiedTypes();
List<Type> list = new ArrayList<Type>(sts.size());
for (Type st : sts) {
// recurse to intersected types
addToIntersection(list, inferTypeArg(tp, paramType, st.substitute(paramTypeArgs, paramVariances), covariant, contravariant, findingUpperBounds, visited, argNode), unit);
}
return intersectionOrNull(list);
} else {
Type supertype = argType.getSupertype(paramTypeDec);
if (supertype != null) {
List<Type> list = new ArrayList<Type>(2);
Type pqt = paramType.getQualifyingType();
Type sqt = supertype.getQualifyingType();
if (pqt != null && sqt != null) {
// recurse to qualifying types
addToUnionOrIntersection(findingUpperBounds, list, inferTypeArg(tp, pqt, sqt, covariant, contravariant, findingUpperBounds, visited, argNode));
}
inferTypeArg(tp, paramType, supertype, covariant, contravariant, findingUpperBounds, list, visited, argNode);
return unionOrIntersectionOrNull(findingUpperBounds, list);
} else {
return null;
}
}
} else {
return null;
}
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration 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.TypeDeclaration in project ceylon by eclipse.
the class TypeArgumentVisitor method visit.
@Override
public void visit(Tree.Enumerated that) {
TypeDeclaration occ = beginConstructor(that.getEnumerated());
super.visit(that);
endConstructor(occ);
}
use of org.eclipse.ceylon.model.typechecker.model.TypeDeclaration in project ceylon by eclipse.
the class TypeHierarchyVisitor method getOrBuildType.
/*private void removeTrailing(String trailingString, StringBuilder sb) {
final int length = sb.length();
sb.delete(length-trailingString.length(), length);
}*/
private Type getOrBuildType(TypeDeclaration declaration) {
Type type = types.get(new TypeDeclKey(declaration));
if (type == null) {
type = new Type();
type.declaration = declaration;
for (Declaration member : declaration.getMembers()) {
if (!(member instanceof FunctionOrValue || member instanceof Class) || isConstructor(member) || member.isStatic() || isAbstraction(member)) {
continue;
}
if (declaration.isNative() && member.isNative()) {
// Make sure we get the right member declaration (the one for the same backend as its container)
Backends backends = declaration.getNativeBackends();
member = getNativeDeclaration(member, backends);
if (member == null) {
continue;
}
}
final String name = member.getName();
Type.Members members = type.membersByName.get(name);
if (members == null) {
members = new Type.Members();
members.name = name;
type.membersByName.put(name, members);
}
if (member.isActual()) {
members.actuals.add(member);
if (!member.isFormal()) {
members.actualsNonFormals.add(member);
}
}
if (member.isFormal()) {
members.formals.add(member);
}
/*if (!member.isFormal() && member.isInterfaceMember()) {
members.concretesOnInterfaces.add(member);
}*/
if (member.isDefault()) {
members.defaults.add(member);
}
if (!member.isFormal() && !member.isDefault() && member.isShared()) {
members.nonFormalsNonDefaults.add(member);
}
if (member.isShared()) {
members.shared.add(member);
}
}
types.put(new TypeDeclKey(declaration), type);
}
return type;
}
Aggregations