use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class InheritanceVisitor method checkCaseType.
void checkCaseType(TypeDeclaration type, Tree.StaticType ct, TypeDeclaration caseTypeDec) {
if (caseTypeDec instanceof ClassOrInterface && ct instanceof Tree.SimpleType && caseTypeDec.isParameterized()) {
Tree.SimpleType t = (Tree.SimpleType) ct;
Tree.TypeArgumentList tal = t.getTypeArgumentList();
List<Tree.Type> args = tal == null ? Collections.<Tree.Type>emptyList() : tal.getTypes();
List<TypeParameter> typeParameters = caseTypeDec.getTypeParameters();
Set<TypeParameter> used = new HashSet<TypeParameter>();
for (int i = 0; i < typeParameters.size(); i++) {
TypeParameter typeParameter = typeParameters.get(i);
Type argType;
Node node;
String typeArg;
if (i < args.size()) {
Tree.Type arg = args.get(i);
argType = arg.getTypeModel();
node = arg;
typeArg = "type argument";
} else {
argType = typeParameter.getDefaultTypeArgument();
node = tal;
typeArg = "default type argument '" + argType.asString(node.getUnit()) + "' of '" + typeParameter.getName() + "' ";
}
if (argType != null) {
TypeDeclaration argTypeDec = argType.getDeclaration();
if (argType.isTypeParameter()) {
TypeParameter tp = (TypeParameter) argTypeDec;
if (!tp.getDeclaration().equals(type)) {
node.addError(typeArg + "is not a type parameter of the enumerated type: '" + tp.getName() + "' is not a type parameter of '" + type.getName() + "'");
} else if (!used.add(tp)) {
node.addError("type parameter of the enumerated type is used twice as a type argument: '" + argTypeDec.getName());
}
} else if (typeParameter.isCovariant()) {
checkAssignable(typeParameter.getType(), argType, node, typeArg + " is not an upper bound of the type parameter '" + typeParameter.getName() + "' ");
} else if (typeParameter.isContravariant()) {
checkAssignable(argType, typeParameter.getType(), node, typeArg + " is not a lower bound of the type parameter '" + typeParameter.getName() + "' ");
} else {
node.addError(typeArg + "is not a type parameter of the enumerated type: '" + argTypeDec.getName() + "'");
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class LocalDeclarationVisitor method visit.
@Override
public void visit(Tree.ClassOrInterface that) {
ClassOrInterface model = that.getDeclarationModel();
visitLocalDecl(that);
Map<String, Integer> oldLocalNames = null;
if (model != null && !model.isAlias()) {
oldLocalNames = localNames;
localNames = new HashMap<String, Integer>();
}
super.visit(that);
if (model != null && !model.isAlias()) {
localNames = oldLocalNames;
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class TypeHierarchyVisitor method visit.
@Override
public void visit(Tree.ClassOrInterface that) {
super.visit(that);
ClassOrInterface classOrInterface = that.getDeclarationModel();
if (!classOrInterface.isAlias()) {
boolean concrete = !classOrInterface.isAbstract() && !classOrInterface.isFormal();
List<Type> orderedTypes = sortDAGAndBuildMetadata(classOrInterface, that);
if (concrete) {
checkForFormalsNotImplemented(that, orderedTypes, (Class) classOrInterface);
}
checkForDoubleMemberInheritanceNotOverridden(that, orderedTypes, classOrInterface);
checkForDoubleMemberInheritanceWoCommonAncestor(that, orderedTypes, classOrInterface);
}
validateMemberRefinement(that, classOrInterface);
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface in project ceylon by eclipse.
the class TypeHierarchyVisitor method validateMemberRefinement.
private void validateMemberRefinement(Node that, TypeDeclaration td) {
if (!td.isInconsistentType() && td instanceof ClassOrInterface && !td.isAbstract() && !td.isAlias() && // resulting in multiple errors
!that.hasErrors()) {
Set<String> errors = new HashSet<String>();
for (TypeDeclaration std : td.getSupertypeDeclarations()) {
for (Declaration d : std.getMembers()) {
if (d.isShared() && !d.isStatic() && !isConstructor(d) && !isOverloadedVersion(d) && isResolvable(d) && !errors.contains(d.getName())) {
Declaration r = td.getMember(d.getName(), null, false);
// to the user!
if (r != null && !r.refines(d) && // is a dupe declaration
!r.getContainer().equals(td) && !((std instanceof Interface || r.isInterfaceMember()) && isDefinedInJava(std) && isDefinedInJava(r))) {
TypeDeclaration ctd = (TypeDeclaration) r.getContainer();
that.addError("member '" + d.getName() + "' is inherited ambiguously by '" + td.getName() + "' from '" + std.getName() + "' and a different generic instantiation of '" + ctd.getName() + "' and is not refined by '" + td.getName() + "' (refine '" + d.getName() + "' to satisfy both instantiations of '" + ctd.getName() + "')", 350);
errors.add(d.getName());
}
}
}
}
}
}
use of org.eclipse.ceylon.model.typechecker.model.ClassOrInterface 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);
}
}
Aggregations