/*
* This file is part of the X10 project (http://x10-lang.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* (C) Copyright IBM Corporation 2006-2010.
*/
package x10.ast;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.HashSet;
import polyglot.ast.Block;
import polyglot.ast.ClassBody;
import polyglot.ast.ClassDecl_c;
import polyglot.ast.ClassMember;
import polyglot.ast.ConstructorDecl;
import polyglot.ast.Expr;
import polyglot.ast.FlagsNode;
import polyglot.ast.Formal;
import polyglot.ast.Id;
import polyglot.ast.MethodDecl;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Stmt;
import polyglot.ast.Term;
import polyglot.ast.TypeNode;
import polyglot.ast.Special;
import polyglot.ast.Field;
import polyglot.ast.Call;
import polyglot.frontend.Job;
import polyglot.frontend.Source;
import polyglot.main.Reporter;
import polyglot.types.ClassDef;
import polyglot.types.ClassType;
import polyglot.types.ConstructorDef;
import polyglot.types.ContainerType;
import polyglot.types.Context;
import polyglot.types.Def;
import polyglot.types.FieldDef;
import polyglot.types.FieldInstance;
import polyglot.types.Flags;
import polyglot.types.LazyRef;
import polyglot.types.LazyRef_c;
import polyglot.types.LocalDef;
import polyglot.types.MemberDef;
import polyglot.types.TypeSystem_c;
import polyglot.types.Name;
import polyglot.types.ObjectType;
import polyglot.types.QName;
import polyglot.types.Ref;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import polyglot.util.CodeWriter;
import polyglot.util.CollectionUtil;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import polyglot.util.TypedList;
import polyglot.visit.CFGBuilder;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.PruningVisitor;
import polyglot.visit.TypeBuilder;
import polyglot.visit.TypeChecker;
import x10.errors.Errors;
import x10.extension.X10Del;
import x10.extension.X10Del_c;
import x10.types.MacroType;
import x10.types.ParameterType;
import x10.types.TypeDef;
import x10.types.TypeParamSubst;
import x10.types.X10ClassDef;
import x10.types.X10ClassDef_c;
import x10.types.X10ClassType;
import x10.types.X10ParsedClassType_c;
import x10.types.X10FieldInstance;
import x10.types.X10LocalDef;
import x10.types.X10MethodDef;
import x10.types.MethodInstance;
import x10.types.X10ParsedClassType;
import x10.types.X10TypeEnv_c;
import x10.types.constraints.CConstraint;
import x10.types.constraints.ConstraintManager;
import x10.types.constraints.TypeConstraint;
import x10.util.Synthesizer;
import x10.visit.ChangePositionVisitor;
/**
* The same as a Java class, except that it needs to handle properties.
* Properties are converted into public final instance fields immediately.
* TODO: Use the retType for the class during type checking.
* @author vj
*
*/
public class X10ClassDecl_c extends ClassDecl_c implements X10ClassDecl {
protected FlagsNode flags;
protected Id name;
protected TypeNode superClass;
protected List<TypeNode> interfaces;
protected ClassBody body;
protected ConstructorDef defaultCI;
protected X10ClassDef type;
List<PropertyDecl> properties;
public List<PropertyDecl> properties() { return properties; }
public X10ClassDecl properties(List<PropertyDecl> ps) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.properties = new ArrayList<PropertyDecl>(ps);
return n;
}
List<TypeParamNode> typeParameters;
public List<TypeParamNode> typeParameters() { return typeParameters; }
public X10ClassDecl typeParameters(List<TypeParamNode> ps) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.typeParameters = new ArrayList<TypeParamNode>(ps);
return n;
}
protected DepParameterExpr classInvariant;
protected X10ClassDecl_c(Position pos, FlagsNode flags, Id name,
List<TypeParamNode> typeParameters,
List<PropertyDecl> properties,
DepParameterExpr tci,
TypeNode superClass,
List<TypeNode> interfaces, ClassBody body) {
super(pos, flags, name, superClass, interfaces, body);
this.typeParameters = TypedList.copyAndCheck(typeParameters, TypeParamNode.class, true);
this.properties = TypedList.copyAndCheck(properties, PropertyDecl.class, true);
this.classInvariant = tci;
assert(flags != null && name != null && interfaces != null && body != null);
this.flags = flags;
this.name = name;
this.superClass = superClass;
this.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true);
this.body = body;
// this.superClass = superClass;
// this.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true);
}
// TODO: do not strip out dependent clauses of parameter types
/** Strip out dependent clauses. */
/* public TypeNode simplify(TypeNode tn) {
if (tn == null)
return null;
return (TypeNode) tn.visit(new NodeVisitor() {
@Override
// public Node override(Node n) {
// if (n instanceof Expr || n instanceof Stmt || n instanceof DepParameterExpr)
// return n;
// return null;
//// if (n instanceof TypeNode || n instanceof QualifierNode || n instanceof Formal || n instanceof TypeParamNode)
//// return null;
//// return n;
// }
public Node leave(Node old, Node n, NodeVisitor v) {
if (n instanceof AmbDepTypeNode) {
AmbDepTypeNode adtn = (AmbDepTypeNode) n;
return adtn.constraint(null);
}
if (n instanceof AmbMacroTypeNode) {
AmbMacroTypeNode adtn = (AmbMacroTypeNode) n;
if (adtn.typeArgs().size() > 0) {
// Just remove the value args and constraint; keep the type args.
return adtn.args(Collections.EMPTY_LIST);
}
// Remove the type args, value args, and constraint.
X10AmbTypeNode atn = ((X10NodeFactory) Globals.NF()).X10AmbTypeNode(n.position(), adtn.prefix(), adtn.name());
return atn;
}
return n;
}
});
}*/
public DepParameterExpr classInvariant() {
return classInvariant;
}
public X10ClassDecl classInvariant(DepParameterExpr tn) {
if (this.classInvariant == tn) {
return this;
}
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.classInvariant = tn;
return n;
}
@Override
protected void setSuperClass(TypeSystem ts, ClassDef thisType) {
TypeNode superClass = this.superClass;
final TypeSystem xts = (TypeSystem) ts;
// We need to lazily set the superclass, otherwise we go into an infinite loop
// during bootstrapping: Object, refers to Int, refers to Object, ...
final LazyRef<Type> superRef = Types.lazyRef(null);
if (flags().flags().isInterface()) {
thisType.superType(null);
}
else if (superClass == null) {
// [DC] no root for classes anymore
thisType.superType(null);
}
else {
superSetSuperClass(ts, thisType);
}
}
private void superSetSuperClass(TypeSystem ts, ClassDef thisType) {
TypeNode superClass = this.superClass;
Reporter reporter = ts.extensionInfo().getOptions().reporter;
if (superClass != null) {
Ref<? extends Type> t = superClass.typeRef();
if (reporter.should_report(Reporter.types, 3))
reporter.report(3, "setting superclass of " + this.type + " to " + t);
thisType.superType(t);
}
else {
// the superclass was not specified, and the type is not the same
// as ts.Object() (which is typically java.lang.Object)
// As such, the default superclass is ts.Object().
if (reporter.should_report(Reporter.types, 3))
reporter.report(3, "setting superclass of " + this.type + " to " + null);
thisType.superType(null);
}
}
@Override
protected void setInterfaces(TypeSystem ts, ClassDef thisType) {
final TypeSystem xts = (TypeSystem) ts;
Reporter reporter = xts.extensionInfo().getOptions().reporter;
// For every struct and interface, add the implicit Any interface.
Flags flags = flags().flags();
if (flags.isStruct()
|| (flags.isInterface() && ! name.toString().equals("Any"))
|| xts.isParameterType(thisType.asType())) {
thisType.addInterface(xts.lazyAny());
}
List<TypeNode> interfaces = this.interfaces;
for (TypeNode tn : interfaces) {
Ref<? extends Type> t = tn.typeRef();
if (reporter.should_report(Reporter.types, 3))
reporter.report(3, "adding interface of " + thisType + " to " + t);
thisType.addInterface(t);
}
}
public X10ClassDecl flags(FlagsNode flags) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.flags = flags;
return n;
}
public X10ClassDecl name(Id name) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.name = name;
return n;
}
public X10ClassDecl superClass(TypeNode superClass) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.superClass = superClass;
return n;
}
public X10ClassDecl body(ClassBody body) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.body = body;
return n;
}
public X10ClassDecl interfaces(List<TypeNode> interfaces) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true);
return n;
}
public X10ClassDecl classDef(X10ClassDef type) {
if (type == this.type) return this;
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.type = type;
return n;
}
public X10ClassDef classDef() {
return type;
}
@Override
public Context enterScope(Context c) {
c = c.pushCode(classDef());
return c.pushBlock();
}
@Override
public Context enterChildScope(Node child, Context c) {
X10ClassDef_c type = (X10ClassDef_c) this.type;
if (child != this.body ) {
if (child == this.classInvariant) {
c = c.pushClass(type, type.asType());
} else {
c = c.pushSuperTypeDeclaration(type);
// Add this class to the context, but don't push a class scope.
// This allows us to detect loops in the inheritance
// hierarchy, but avoids an infinite loop.
c = c.pushBlock();
c.addNamed(type.asType());
// add class invariant, XTENLANG-3125
if (classInvariant != null) {
c.addConstraint(type.classInvariant()); // is this needed too?
c.setCurrentTypeConstraint(classInvariant.typeConstraint());
}
}
// Add type parameters
for (ParameterType t : type.typeParameters()) {
c.addNamed(t);
}
for (PropertyDecl pd : properties) {
FieldDef fd = pd.fieldDef();
c.addVariable(fd.asInstance());
if (pd==child)
break; // do not add downstream properties
}
} else {
c = c.pushClass(type, type.asType());
// Add type parameters
for (ParameterType t : type.typeParameters()) {
c.addNamed(t);
}
// The class invariant should be added only when entering
// children (field, method) that are not static.
/* DepParameterExpr v = classInvariant();
if (v != null) {
Ref<TypeConstraint> tc = v.typeConstraint();
if (tc != null) {
c.setCurrentTypeConstraint(tc); // todo: what about setCurrentConstraint ?
}
}*/
}
return super.enterChildScope(child, c);
}
public Node visitSignature(NodeVisitor v) {
FlagsNode flags = (FlagsNode) visitChild(this.flags, v);
Id name = (Id) visitChild(this.name, v);
List<TypeParamNode> tps = visitList(this.typeParameters, v);
TypeNode superClass = (TypeNode) visitChild(this.superClass, v);
List<TypeNode> interfaces = visitList(this.interfaces, v);
DepParameterExpr ci = (DepParameterExpr) visitChild(this.classInvariant, v);
List<PropertyDecl> ps = visitList(this.properties, v);
ClassBody body = this.body;
X10ClassDecl_c n = (X10ClassDecl_c) reconstruct(flags, name, superClass, interfaces, body);
if (!CollectionUtil.allEqual(tps, this.typeParameters) || !CollectionUtil.allEqual(ps, this.properties) || ci != this.classInvariant) {
if (n == this) n = (X10ClassDecl_c) n.copy();
n.typeParameters = new ArrayList<TypeParamNode>(tps);
n.properties = new ArrayList<PropertyDecl>(ps);
n.classInvariant = ci;
}
return n;
}
@Override
public X10ClassDecl_c preBuildTypes(TypeBuilder tb) {
X10ClassDecl_c n = (X10ClassDecl_c) superPreBuildTypes(tb);
final X10ClassDef def = (X10ClassDef) n.type;
def.setThisDef(tb.typeSystem().thisDef(n.position(), Types.ref(def.asType())));
TypeBuilder childTb = tb.pushClass(def);
List<TypeParamNode> pas = n.visitList(n.typeParameters, childTb);
// [IP] Don't do this here. It's the job of X10InnerClassRemover
// pas = new LinkedList<TypeParamNode>(pas);
//
// if (def.isMember() && ! def.flags().isStatic()) {
// X10ClassDef outer = (X10ClassDef) Types.get(def.outer());
// while (outer != null) {
// X10NodeFactory nf = (X10NodeFactory) tb.nodeFactory();
// for (int i = 0; i < outer.typeParameters().size(); i++) {
// ParameterType pt = outer.typeParameters().get(i);
// TypeParamNode tpn = nf.TypeParamNode(pt.position(), nf.Id(pt.position(), pt.name()));
// tpn = tpn.variance(outer.variances().get(i));
// tpn = (TypeParamNode) n.visitChild(tpn, childTb);
// pas.add(tpn);
// }
//
// if (outer.isMember())
// outer = (X10ClassDef) Types.get(outer.outer());
// else
// outer = null;
// }
// }
n = (X10ClassDecl_c) n.typeParameters(pas);
for (TypeParamNode tpn : n.typeParameters()) {
def.addTypeParameter(tpn.type(), tpn.variance());
}
///* [DC] going to hack the typesystem to allow calls to these special Any methods even if they don't exist.
// [DC] actually, no. going to do that for objects but not structs, and do something else for structs later
if (flags().flags().isStruct())
n = x10.util.Struct.addStructMethods(tb,n);
//*/
//I need a way to access the outer instance when generating dynamic_checks.
//For example:
//class A(a:Any) {
// class B(b:Any) {
// def m() {a!=null} {...}
// }
//}
//class Test {
// def test(b:B) {
// b.m(); // with DYNAMIC_CHECKS it will check that "a!=null", by dynamically inserting this code: "if (!(b.OUTER.a!=null)) throw new FailedDynamicCheckException(); b.m()"
// }
//}
//However, we don't have a way to access the outer instance!
//So we generate methods that return it.
//
// adding methods to access the outer instances (used in Desugarer.desugarCall)
// The method name includes both the container name and the qualifier name to handle this nasty case:
//class A[T] {
// public final def A$$A$this() = A.this;
// class Inner extends A[Int] {
// public final def Inner$$A$this() = A.this; // the return type is different!
// public final def Inner$$Inner$this() = Inner.this;
// }
//}
// Another simpler example:
// class A {
// public final def A$$A$this() = A.this;
// class B {
// public final def B$$B$this() = B.this;
// public final def B$$A$this() = A.this;
// }
// class D extends B {
// public final def D$$D$this() = D.this;
// public final def D$$A$this() = A.this;
// }
// static class C {
// public final def C$$C$this() = C.this;
// }
// }
{
final Position pos = n.position().markCompilerGenerated();
final Flags flags = Flags.PUBLIC.Final();
final NodeFactory nf = tb.nodeFactory();
final QName containerName = def.fullName();
ClassType curr = def.asType();
while (curr!=null) {
if (curr.flags().isInterface())
break;
final UnknownTypeNode returnType = nf.UnknownTypeNode(pos);
final QName fullName = curr.fullName();
MethodDecl md = nf.MethodDecl(pos,nf.FlagsNode(pos,flags),returnType,nf.Id(pos,getThisMethod(containerName,fullName)),Collections.<Formal>emptyList(),
nf.Block(pos,nf.Return(pos,nf.Special(pos, Special.Kind.THIS, nf.CanonicalTypeNode(pos, curr)))));
n = (X10ClassDecl_c) n.body(n.body().addMember(md));
if (curr.flags().isStatic() || !curr.isMember()) break; // a non-member class doesn't have an outer instance
curr = curr.outer();
}
}
return n;
}
public static Name getThisMethod(QName containerName, QName n) {
return Name.make(
containerName.toString().replace('.','$')+ "$"+ "$this"
+"$"+ n.toString().replace('.','$')
);
}
private SemanticException errorInAST;
public SemanticException errorInAST() {
return errorInAST;
}
public X10ClassDecl_c errorInAST(SemanticException error) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.errorInAST = error;
return n;
}
public static final QName X10_INTEROP_JAVA = QName.make("x10.interop.Java");
public static final Name JAVA_ARRAY = Name.make("array");
private X10ClassDecl_c superPreBuildTypes(TypeBuilder tb) {
// XTENLANG-2118: Intercept some known Java types
if (name.id().equals(JAVA_ARRAY) && tb.currentClass() != null && tb.currentClass().fullName().equals(X10_INTEROP_JAVA))
tb = tb.pushClass(tb.typeSystem().JavaArray().def());
else
tb = tb.pushClass(position(), name().position(), flags.flags(), name.id(), errorInAST);
X10ClassDef type = tb.currentClass();
// Member classes of interfaces are implicitly public and static.
if (type.isMember() && type.outer().get().flags().isInterface()) {
type.flags(type.flags().Public().Static());
}
// Member interfaces are implicitly static.
if (type.isMember() && type.flags().isInterface()) {
type.flags(type.flags().Static());
}
// Interfaces are implicitly abstract.
if (type.flags().isInterface()) {
type.flags(type.flags().Abstract());
}
X10ClassDecl_c n = this;
FlagsNode flags = (FlagsNode) n.visitChild(n.flags, tb);
Id name = (Id) n.visitChild(n.name, tb);
TypeNode superClass = (TypeNode) n.visitChild(n.superClass, tb);
List<TypeNode> interfaces = n.visitList(n.interfaces, tb);
n = n.reconstruct(flags, name, superClass, interfaces, n.body);
n.setSuperClass(tb.typeSystem(), type);
n.setInterfaces(tb.typeSystem(), type);
n = (X10ClassDecl_c) n.classDef(type).flags(flags.flags(type.flags()));
return n;
}
@Override
public X10ClassDecl_c postBuildTypes(TypeBuilder tb) {
X10ClassDecl_c n = (X10ClassDecl_c) this.copy();
if (n.defaultConstructorNeeded()) {
ConstructorDecl cd = n.createDefaultConstructor(type, tb.typeSystem(), tb.nodeFactory());
TypeBuilder tb2 = tb.pushClass(n.type);
cd = (ConstructorDecl) tb2.visitEdge(n, cd);
n = (X10ClassDecl_c) n.body(n.body().addMember(cd));
n.defaultCI = cd.constructorDef();
}
final X10ClassDef def = (X10ClassDef) n.type;
TypeBuilder childTb = tb.pushClass(def);
n = (X10ClassDecl_c) X10Del_c.visitAnnotations(n, childTb);
List<AnnotationNode> as = ((X10Del) n.del()).annotations();
if (as != null) {
List<Ref<? extends Type>> ats = new ArrayList<Ref<? extends Type>>(as.size());
for (AnnotationNode an : as) {
ats.add(an.annotationType().typeRef());
}
((X10ClassDef) n.type).setDefAnnotations(ats);
}
List<PropertyDecl> ps = visitList(n.properties, childTb);
n = (X10ClassDecl_c) n.properties(ps);
final DepParameterExpr ci = (DepParameterExpr) n.visitChild(n.classInvariant, childTb);
n = (X10ClassDecl_c) n.classInvariant(ci);
final LazyRef<CConstraint> c = new LazyRef_c<CConstraint>(ConstraintManager.getConstraintSystem().makeCConstraint());
final X10ClassDecl_c nn = n;
c.setResolver(new Runnable() {
public void run() {
CConstraint x = ConstraintManager.getConstraintSystem().makeCConstraint();
if (ci != null) {
CConstraint xi = ci.valueConstraint().get();
if (xi != null && ! xi.valid())
x.addIn(xi);
}
c.update(x);
}
});
def.setClassInvariant(c);
final LazyRef<TypeConstraint> tc = new LazyRef_c<TypeConstraint>(new TypeConstraint());
// Set the type bounds for the def.
tc.setResolver(new Runnable() {
public void run() {
if (ci != null) {
TypeConstraint ti = ci.typeConstraint().get();
tc.update(ti.copy());
}
}
});
def.setTypeBounds(tc);
return n;
}
boolean contains(List<ClassMember> list, Id xName, List<Formal> xf) {
OUTER: for (ClassMember yy : list) {
MethodDecl y = (MethodDecl) yy;
List<Formal> yf = y.formals();
if (xName.equals(y.name()) && xf.size() == yf.size()) {
for (int i=0; i < xf.size(); ++i) {
if (! (xf.get(i).equals(yf.get(i))))
continue OUTER;
}
return true;
}
}
return false;
}
/**
* If the class is abstract, and does not implement a method specified by an interface,
* add an abstract declaration for this method.
* @param parent
* @param tc
* @param childtc
* @return
*/
public Node adjustAbstractMethods( ContextVisitor tc) {
// [DC] it seems this function exists so that one can dispatch through an
// abstract method in the c++ backend using the standard vtable dispatch mechanism
// rather than having to go through itables. This makes the codegen simpler and is faster at runtime.
X10ClassDecl_c n = this;
if (n.flags().flags().isInterface())
return n;
if (! n.flags().flags().isAbstract())
return n;
Position CG = Position.compilerGenerated(body().position());
TypeSystem xts = tc.typeSystem();
NodeFactory xnf = (NodeFactory) tc.nodeFactory();
X10ClassType targetType = (X10ClassType) n.classDef().asType();
List<X10ClassType> interfaces = xts.allImplementedInterfaces(targetType, false);
LinkedList<MethodInstance> candidates = new LinkedList<MethodInstance>();
for (X10ClassType intface : interfaces) {
List<MethodInstance> oldMethods = intface.methods();
for (MethodInstance mi : oldMethods) {
// [DC] leave these guys out of the picture -- backends handle them specially
// testing mi.container().isAny() does not work since an interface I can redeclare these methods as abstract, in which
// case their container is I, not Any
if (mi.name().toString().equals("toString") && mi.formalNames().isEmpty()) continue;
if (mi.name().toString().equals("hashCode") && mi.formalNames().isEmpty()) continue;
if (mi.name().toString().equals("typeName") && mi.formalNames().isEmpty()) continue;
if (mi.name().toString().equals("equals") && mi.formalNames().size()==1 && mi.formalTypes().get(0).isAny()) continue;
MethodInstance mj = xts.findImplementingMethod(targetType, mi, true, tc.context());
if (mj == null) { // This method is not already defined for this class
candidates.add(mi);
}
}
} // interfaces
// Remove overridden methods -- happens with covariant return types.
List<MethodInstance> results = new LinkedList<MethodInstance>();
Context context = xts.createContext();
OUTER: while (! candidates.isEmpty()) {
MethodInstance mi = candidates.removeFirst();
for (MethodInstance other : candidates) {
if (other.canOverride(mi, context))
continue OUTER;
}
results.add(mi);
}
Synthesizer synth = new Synthesizer(xnf, xts);
for (MethodInstance mi : results) {
Id name = xnf.Id(CG, mi.name());
TypeParamSubst subst = ((X10ParsedClassType) mi.container()).subst();
List<LocalDef> formalNames = new ArrayList<LocalDef>();
for (LocalDef f : ((X10MethodDef) mi.def()).formalNames()) {
X10LocalDef tf = (X10LocalDef) f.copy();
tf.setType(subst.reinstantiate(f.type()));
formalNames.add(tf);
}
n = synth.addSyntheticMethod(n,
mi.flags().Public().Abstract(),
((X10MethodDef) mi.def()).typeParameters(),
mi.name(),
formalNames,
mi.throwTypes(),
mi.returnType(), null);
}
return n;
}
/**
* If the class does not have a super type and does not define a method from Any, add a default one.
*/
public Node addDefaultAnyMethods( ContextVisitor tc) {
X10ClassDecl_c n = this;
if (n.flags().flags().isInterface())
return n;
if (n.flags().flags().isStruct())
return n;
if (n.superClass() != null)
return n;
TypeSystem xts = tc.typeSystem();
NodeFactory xnf = (NodeFactory) tc.nodeFactory();
X10ClassType targetType = (X10ClassType) n.classDef().asType();
LinkedList<MethodInstance> results = new LinkedList<MethodInstance>();
X10ClassType intface = xts.Any();
for (MethodInstance mi : xts.Any().methods()) {
MethodInstance mj = xts.findImplementingMethod(targetType, mi, true, tc.context());
if (mj == null) { // This method is not already defined for this class
results.add(mi);
}
}
Position CG = Position.compilerGenerated(body().position());
Synthesizer synth = new Synthesizer(xnf, xts);
for (MethodInstance mi : results) {
Id name = xnf.Id(CG, mi.name());
List<LocalDef> formalNames = new ArrayList<LocalDef>();
for (LocalDef f : ((X10MethodDef) mi.def()).formalNames()) {
X10LocalDef tf = (X10LocalDef) f.copy();
tf.setType(f.type());
formalNames.add(tf);
}
Type system = xts.System();
Name system_name = null;
X10Call call = null;
try {
if (mi.name().toString().equals("hashCode")) {
List<Expr> args = Collections.<Expr>singletonList(xnf.Special(CG, Special.THIS).type(targetType));
call = (X10Call) synth.makeStaticCall(CG, system, Name.make("identityHashCode"), args, mi.returnType(), tc.context());
}
//if (mi.name().toString().equals("typeName")) system_name = Name.make("identityTypeName");
//if (mi.name().toString().equals("toString")) system_name = Name.make("identityToString");
//if (mi.name().toString().equals("equals")) system_name = Name.make("identityEquals");
//call = null;
if (call != null) {
assert call != null : mi.name().toString();
System.out.println("Adding hashCode method... calling: " + call);
n = synth.addSyntheticMethod(n,
Flags.PUBLIC,
((X10MethodDef) mi.def()).typeParameters(),
mi.name(),
formalNames,
mi.throwTypes(),
mi.returnType(), xnf.Block(CG,xnf.Return(CG, call)));
}
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
}
return n;
}
public Node typeCheckClassInvariant(Node parent, ContextVisitor tc, TypeChecker childtc) {
X10ClassDecl_c n = this;
DepParameterExpr classInvariant = (DepParameterExpr) n.visitChild(n.classInvariant, childtc);
n = (X10ClassDecl_c) n.classInvariant(classInvariant);
// TODO: Add check that the invariant established by this class is adequate
// to entail the invariants associated with all interfaces (after applying
// a substitution which replaces all fields specified in the interface with the fields
// implementing them in the class).
return n;
}
public Node typeCheckProperties(Node parent, ContextVisitor tc, TypeChecker childtc) {
X10ClassDecl_c n = this;
List<TypeParamNode> typeParameters = n.visitList(n.typeParameters, childtc);
n = (X10ClassDecl_c) n.typeParameters(typeParameters);
List<PropertyDecl> properties = n.visitList(n.properties, childtc);
n = (X10ClassDecl_c) n.properties(properties);
return n;
}
public Node typeCheckOverride(Node parent, ContextVisitor tc) {
X10ClassDecl_c n = this;
NodeVisitor v = tc.enter(parent, n);
if (v instanceof PruningVisitor) {
return this;
}
TypeChecker childtc = (TypeChecker) v;
ContextVisitor oldtc = (ContextVisitor) tc.shallowCopy();
n = (X10ClassDecl_c) n.typeCheckSupers(tc, childtc);
TypeSystem xts = tc.typeSystem();
if (superClass != null) {
Ref<? extends Type> stref = superClass.typeRef();
try {
checkSuperclass(xts, stref);
} catch (SemanticException e) {
X10ClassType uc = xts.createFakeClass(QName.make(superClass.nameString()), e);
for (ConstructorDef cd : classDef().constructors()) {
ConstructorDef ucd = (ConstructorDef) cd.copy();
ucd.setContainer(Types.ref(uc));
uc.def().addConstructor(ucd);
}
((Ref<Type>) stref).update(uc);
}
}
for (TypeNode itn : interfaces()) {
Ref<? extends Type> tref = itn.typeRef();
try {
checkSuperinterface(xts, tref);
} catch (SemanticException e) {
X10ClassType uc = xts.createFakeClass(QName.make(itn.nameString()), e);
uc.def().flags(uc.def().flags().Interface());
((Ref<Type>) tref).update(uc);
}
}
n = (X10ClassDecl_c) n.typeCheckProperties(parent, tc, childtc);
n = (X10ClassDecl_c) n.typeCheckClassInvariant(parent, tc, childtc);
// have to run this before adjustAbstractMethods so that it doesn't create an abstract method for these guys
//n = (X10ClassDecl_c) n.addDefaultAnyMethods(oldtc);
n = (X10ClassDecl_c) n.adjustAbstractMethods(oldtc);
n = (X10ClassDecl_c) n.typeCheckBody(parent, tc, childtc);
n = (X10ClassDecl_c) X10Del_c.visitAnnotations(n, childtc);
// Make sure the node and type are consistent WRT super types.
NodeFactory nf = tc.nodeFactory();
if (type.superType() != null) {
if (!((X10ClassDef) type).isStruct()) {
if ((Types.isX10Struct(type.superType().get()))) {
Errors.issue(tc.job(),
new Errors.ClassMustHaveClassSupertype(type.superType(),
type,
position()));
}
}
}
if (n.superClass == null && type.superType() != null) {
n = (X10ClassDecl_c) n.superClass(nf.CanonicalTypeNode(
(body!=null ? body.position().startOf() : position()).markCompilerGenerated(), type.superType()));
}
List<TypeNode> newInterfaces = new ArrayList<TypeNode>();
for (Ref<? extends Type> t : type.interfaces()) {
boolean added = false;
for (int i = 0; i < n.interfaces.size(); i++) {
TypeNode tn = n.interfaces.get(i);
if (tn.typeRef() == t) {
newInterfaces.add(tn);
added = true;
continue;
}
}
if (! added) {
TypeNode tn = nf.CanonicalTypeNode(position().markCompilerGenerated(), t);
newInterfaces.add(tn);
}
}
n = (X10ClassDecl_c) n.interfaces(newInterfaces);
if (false) { // todo: this code is useless! it only adds to the lists, without doing any checks!
// Check for duplicate interfaces
/* List<X10ClassType> supers = new ArrayList<X10ClassType>();
LinkedList<Type> worklist = new LinkedList<Type>();
worklist.add(type.asType());
while (! worklist.isEmpty()) {
Type t = worklist.removeFirst();
if (t instanceof X10ClassType) {
supers.add((X10ClassType) t);
}
if (t instanceof ObjectType) {
ObjectType ot = (ObjectType) t;
worklist.add(ot.superClass());
worklist.addAll(ot.interfaces());
}
}*/
}
// Check for instance type definitions -- these are not supported.
for (TypeDef def : ((X10ClassDef) type).memberTypes()) {
MacroType mt = def.asType();
if (mt.container() != null && !mt.flags().isStatic()) {
Errors.issue(tc.job(), new Errors.TypedefMustBeStatic(mt, def.position()), this);
}
}
// fix for XTENLANG-978
// Map<X10ClassDef,X10ClassType> map = CollectionFactory.newHashMap();
// for (X10ClassType ct : supers) {
// X10ClassType t = map.get(ct.x10Def());
// if (t != null) {
// if (!t.typeEquals(ct, tc.context())) {
// String kind = ct.flags().isInterface() ? "interface" : "class";
// Errors.issue(tc.job(),
// new Errors.CannotExtendTwoInstancesSameInterfaceLimitation(t, ct,
// position()));
// }
// }
// map.put(ct.x10Def(), ct);
// }
Flags flags = n.flags().flags();
if (flags.isStruct()) {
if (n.classDef().isInnerClass() && ! flags.isStatic()) {
Errors.issue(tc.job(), new Errors.StructMustBeStatic(n));
n.classDef().setFlags(n.classDef().flags().Static());
n = (X10ClassDecl_c) n.flags(n.flags().flags(flags.Static()));
}
}
n.checkStructMethods(parent, tc);
// a superclass/interface is a covariant position (+)
if (n.superClass!=null) Types.checkVariance(n.superClass, ParameterType.Variance.COVARIANT,tc.job());
for (TypeNode typeNode : n.interfaces)
Types.checkVariance(typeNode, ParameterType.Variance.COVARIANT,tc.job());
// check normal interfaces do not have property fields, but only annotation-interfaces
if (flags.isInterface() && properties.size()>0) {
Type A;
try {
A = xts.systemResolver().findOne(QName.make("x10.lang.annotations.Annotation"));
} catch (SemanticException e) {
throw new InternalCompilerError("Couldn't find x10.lang.annotations.Annotation",e);
}
if (!classDef().asType().isSubtype(A,tc.context())) {
Errors.issue(tc.job(), new SemanticException("Interfaces that do not extend Annotation cannot have property fields. Use property methods instead.",name().position()));
}
}
// check properties are always simpler than their container
if (((X10ClassDef_c)classDef()).hasCircularProperty())
Errors.issue(tc.job(), new SemanticException("A class can only have properties of a 'simpler' type, i.e., there must be an ordering for all types such that if A has a property of type B then B is 'simpler' than A, and if A extends B then B is 'simpler' than A.",name().position()));
return n;
}
// TODO
protected void checkStructMethods(Node parent, ContextVisitor tc) {
}
@Override
protected void checkSupertypeCycles(TypeSystem ts) throws SemanticException {
TypeSystem xts = (TypeSystem) ts;
Ref<? extends Type> stref = type.superType();
checkSuperclass(xts, stref);
for (Ref<? extends Type> tref : type.interfaces()) {
checkSuperinterface(xts, tref);
}
}
protected void checkSuperclass(TypeSystem xts, Ref<? extends Type> stref) throws SemanticException {
if (stref == null)
return;
Type t = stref.get();
t = followDefs(t);
if (xts.hasUnknown(t))
return;
if (! t.isClass() || t.toClass().flags().isInterface()) {
throw new SemanticException("Cannot extend type " + t + "; not a class.", superClass != null ? superClass.position() : name().position());
}
xts.checkCycles((ObjectType) t);
}
protected void checkSuperinterface(TypeSystem xts, Ref<? extends Type> tref) throws SemanticException {
if (tref == null)
return;
Type t = tref.get();
t = followDefs(t);
if (xts.hasUnknown(t))
return;
if (! t.isClass() || ! t.toClass().flags().isInterface()) {
String s = type.flags().isInterface() ? "extend" : "implement";
throw new SemanticException("Cannot " + s + " type " + t + "; not an interface.", name().position());
}
xts.checkCycles((ObjectType) t);
}
protected List<TypeNode> followDefs(List<TypeNode> tns) {
List<TypeNode> newTns = new ArrayList<TypeNode>();
for (TypeNode tn : tns) {
newTns.add(followDefs(tn));
}
return newTns;
}
protected Type followDefs(Type t) {
if (t instanceof MacroType) {
MacroType mt = (MacroType) t;
return followDefs(mt.definedType());
}
return t;
}
protected TypeNode followDefs(TypeNode tn) {
Type t = tn.type();
Type t2 = followDefs(tn.type());
if (t2 != t) {
Ref<? extends Type> r = tn.typeRef();
if (r instanceof LazyRef<?>) {
((LazyRef<Type>) r).update(t2);
return tn;
}
return tn.typeRef(Types.ref(t2));
}
return tn;
}
public Node conformanceCheck(ContextVisitor tc) {
X10ClassDecl_c result = (X10ClassDecl_c) superConformanceCheck(tc);
Context context = (Context) tc.context();
X10ClassDef cd = classDef();
{
CConstraint c = cd.classInvariant().get();
if (c != null && ! c.consistent()) {
Errors.issue(tc.job(), new Errors.InconsistentInvariant(cd, position()));
}
if (c != null && ! c.valid()) {
c = cd.getRealClause();
if (c != null && ! c.consistent()) {
Errors.issue(tc.job(), new Errors.InconsistentInvariant(cd, position()));
}
}
}
// Check that we're in the right file.
if (flags.flags().isPublic() && type.isTopLevel()) {
Job job = tc.job();
if (job != null) {
Source s = job.source();
if (! (s.name().startsWith(type.name() + ".") ||
s.name().endsWith(File.separator + type.name() + ".x10") ||
s.name().endsWith("/" + type.name() + ".x10")))
{
Errors.issue(tc.job(),
new Errors.PublicTypeMustBeDeclaredInX10(type, result.position()));
}
}
}
TypeSystem ts = (TypeSystem) tc.typeSystem();
Type superClass = type.asType().superClass();
if (flags.flags().isInterface() && superClass != null) {
Errors.issue(tc.job(),
new Errors.InterfaceCannotHaveSuperclass(this.type, superClass.position()));
}
if (superClass != null) {
for (PropertyDecl pd : properties()) {
SemanticException ex = null;
try {
FieldInstance fi = ts.findField(superClass, type.asType(), pd.name().id(), tc.context());
if (fi instanceof X10FieldInstance) {
X10FieldInstance xfi = (X10FieldInstance) fi;
if (xfi.isProperty())
ex = new Errors.ClassCannotOverridePropertyOfSuperclass(type, fi, position());
}
}
catch (SemanticException e) {
// not found. That's good.
continue;
}
Errors.issue(tc.job(), ex, this);
}
}
try {
((X10ClassDef) type).checkRealClause();
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
return result;
}
private Node superConformanceCheck(ContextVisitor tc) {
TypeSystem ts = tc.typeSystem();
X10ClassType type = this.type.asType();
Name name = this.name.id();
// The class cannot have the same simple name as any enclosing class.
if (type.isNested()) {
ClassType container = type.outer();
while (container != null) {
if (!container.isAnonymous()) {
Name cname = container.name();
if (cname.equals(name)) {
new Errors.SameNameClass(type,position()).issue(tc.job());
}
}
if (container.isNested()) {
container = container.outer();
}
else {
break;
}
}
}
// A local class name cannot be redeclared within the same
// method, constructor or initializer, and within its scope
final Context context = tc.context();
if (type.isLocal()) {
if (context.isLocal(name)) {
// Something with the same name was declared locally.
// (but not in an enclosing class)
try {
List<Type> nm = context.find(ts.TypeMatcher(name));
for (Type another : nm) {
if (another.isClass() && another.toClass().isLocal()) {
Errors.issue(tc.job(), new Errors.SameNameLocal(type, position()));
}
}
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
}
}
if (type.isMember() && (type.outer().isInnerClass() || type.outer().isLocal() || type.outer().isAnonymous())) {
if (type.flags().isInterface()) {
// check that inner classes do not declare member interfaces
Errors.issue(tc.job(),
new Errors.InnerDeclaredInterface(type, type.outer(), position()));
} else
if (type.flags().isStatic()) {
// Make sure that static members are not declared inside inner classes
Errors.issue(tc.job(),
new Errors.InnerDeclaredStatic(type, type.outer(), position()));
}
}
if (type.superClass() != null && isValidType(type.superClass())) {
if (! type.superClass().isClass() || type.superClass().toClass().flags().isInterface()) {
Errors.issue(tc.job(),
new Errors.ExtendedNonClass(type,
position()));
}
if (type.superClass().toClass().flags().isFinal()) {
Errors.issue(tc.job(),
new Errors.ExtendedFinalClass(type,
position()));
}
}
for (Iterator<TypeNode> i = interfaces.iterator(); i.hasNext(); ) {
TypeNode tn = (TypeNode) i.next();
Type t = tn.type();
if (isValidType(t) && ! (t.isClass() && t.toClass().flags().isInterface())) {
Errors.issue(tc.job(),
new Errors.SuperInterfaceNotInterface(t,type,
tn.position()));
}
}
// check that 2 super-interfaces (or a superclass and superinterface)
// do not cause a method collision (see InterfaceMethodCollision_MustFailCompile.x10)
//interface A { def m():A; }
//interface B { def m():B; }
//abstract class B2 implements B {}
//@ERR interface C1 extends A,B {}
//interface C2 extends A,B { def m():C; }
//@ERR abstract C3 extends B2 implements A {}
// (other kinds of method collisions are checked in MethodDecl_c.overrideMethodCheck)
// optimization: methods in Any&Object cannot cause problems (such errors will be caught in MethodDecl_c)
X10ParsedClassType_c myClassType = (X10ParsedClassType_c) type;
if (interfaces.size()>=1) {
final List<X10ParsedClassType_c> directSuperTypes = new ArrayList<X10ParsedClassType_c>(myClassType.directSuperTypes());
int len = directSuperTypes.size();
for (int i1=0; i1<len; i1++) {
X10ParsedClassType_c it1 = directSuperTypes.get(i1);
// we can skip Any
if (ts.isAny(it1)) continue;
final List<MethodInstance> methods1 = it1.getAllMethods();
if (methods1.size()==0) continue;
for (int i2=i1+1; i2<len; i2++) {
X10ParsedClassType_c it2 = directSuperTypes.get(i2);
if (ts.isAny(it2)) continue;
for (MethodInstance mi : methods1) {
// We need to skip methods defined by "type" because they were already checked against all previous methods, e.g., interface C2 extends A,B { def m():C; }
if (!type.methods(mi.name(), mi.formalTypes(), context).isEmpty())
continue;
final List<MethodInstance> implementedBy = ((TypeSystem_c) ts).implemented(mi, (ContainerType) it2, context);
for (MethodInstance mj : implementedBy) {
if (mi==mj) continue;
checkOverride(tc, ts, context, mi, mj);
}
}
}
}
}
{
// methods with the same erased signature must have the exact same signature (see XTENLANG-547)
Context context2 = context.pushClass(this.type, type);
ArrayList<MethodInstance> allMethods = myClassType.getAllMethods();
for (int i=0; i<allMethods.size(); i++) {
MethodInstance mi = allMethods.get(i);
List<Type> types1 = mi.formalTypes();
int formalNum = types1.size();
if (formalNum ==0) continue;
if (! ts.isAccessible(mi, context2)) continue;
Name name1 = mi.name();
for (int j=i+1; j<allMethods.size(); j++) {
MethodInstance mj = allMethods.get(j);
List<Type> types2 = mj.formalTypes();
if (types2.size()==0) continue;
if (! ts.isAccessible(mj, context2)) continue;
Name name2 = mj.name();
if (name1!=name2) continue;
if (formalNum !=types2.size()) continue;
int typeParamNum = mi.typeParameters().size();
if (typeParamNum !=mj.typeParameters().size()) continue;
boolean isDifferent = false;
for (int p=0; p<formalNum;p++) {
Type t1 = Types.stripConstraints(types1.get(p));
Type t2 = Types.stripConstraints(types2.get(p));
// replace type-parameters in mi with mj, e.g.,
// def m[U](U)
// def m[H](H)
if (typeParamNum!=0) {
List<ParameterType> param1 = (List<ParameterType>) (List) mi.typeParameters();
List<Type> param2 = mj.typeParameters();
TypeParamSubst subst = new TypeParamSubst(ts, param2, param1);
t1 = subst.reinstantiate(t1);
}
if (!ts.typeEquals(t1,t2,context2)) {
isDifferent = true;
break;
}
}
if (isDifferent) continue;
// now we require that one overrides the other
// either mi can override mj, or the opposite.
checkOverride(tc, ts, context2, mi, mj);
}
}
}
try {
if (type.isTopLevel()) {
ts.checkTopLevelClassFlags(type.flags());
}
if (type.isMember()) {
ts.checkMemberClassFlags(type.flags());
}
if (type.isLocal()) {
ts.checkLocalClassFlags(type.flags());
}
}
catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
// Check that the class implements all abstract methods that it needs to.
try {
ts.checkClassConformance(type, enterChildScope(body, context));
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
return this;
}
private void checkOverride(ContextVisitor tc, TypeSystem ts, Context context, MethodInstance mi, MethodInstance mj) {
// either mi can override mj, or the opposite.
try {
// due to covariant return type, the first argument should be the one with return type who is a subtype of the second
MethodInstance mj2 = expandMacros(tc, ts, mi, mj);
ts.checkOverride(mi, mj2, context);
} catch (SemanticException e2) {
try {
MethodInstance mi2 = expandMacros(tc, ts, mj, mi);
ts.checkOverride(mj, mi2, context);
} catch (SemanticException e) {
e.setPosition(this.position());
Errors.issue(tc.job(),e, this);
}
}
}
public static MethodInstance expandMacros(ContextVisitor tc, TypeSystem ts, MethodInstance mi, MethodInstance mj) {
return ((X10TypeEnv_c)ts.env(tc.context())).expandPropertyInMethod(Types.getClassType(mi.container(),ts,tc.context()),mj);
}
protected boolean isValidType(Type type) {
TypeSystem xts = (TypeSystem) type.typeSystem();
return !xts.hasUnknown(type);
}
public Term firstChild() {
return listChild(properties, this.body);
}
/**
* Visit this term in evaluation order.
*/
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
v.visitCFGList(this.properties(), this.body(), ENTRY);
v.visitCFG(this.body(), this, EXIT);
return succs;
}
protected ConstructorDecl createDefaultConstructor(ClassDef _thisType,
TypeSystem ts, final NodeFactory nf)
{
X10ClassDef thisType = (X10ClassDef) _thisType;
Position pos = Position.compilerGenerated(body().position());
NodeFactory xnf = (NodeFactory) nf;
Block block = null;
Ref<? extends Type> superType = thisType.superType();
Stmt s1 = null;
if (superType != null) {
s1 = nf.SuperCall(pos, Collections.<Expr>emptyList());
}
Stmt s2 = null;
List<TypeParamNode> typeFormals = Collections.<TypeParamNode>emptyList();
List<Formal> formals = Collections.<Formal>emptyList();
if (! properties.isEmpty()) {
// build type parameters.
/*typeFormals = new ArrayList<TypeParamNode>(typeParameters.size());
List<TypeNode> typeActuals = new ArrayList<TypeNode>(typeParameters.size());
for (TypeParamNode tp : typeParameters) {
typeFormals.add(xnf.TypeParamNode(pos, tp.name()));
typeActuals.add(xnf.CanonicalTypeNode(pos, tp.type()));
}*/
formals = new ArrayList<Formal>(properties.size());
List<Expr> actuals = new ArrayList<Expr>(properties.size());
ChangePositionVisitor changePositionVisitor = new ChangePositionVisitor(pos);
for (PropertyDecl pd: properties) {
Id name = (Id) pd.name().position(pos);
TypeNode typeNode = (TypeNode) pd.type().copy();
Node newNode = typeNode.visit(changePositionVisitor);
formals.add(xnf.Formal(pos, nf.FlagsNode(pos, Flags.FINAL),
(TypeNode) newNode, name));
actuals.add(xnf.Local(pos, name));
}
s2 = xnf.AssignPropertyCall(pos, Collections.<TypeNode>emptyList(), actuals);
}
block = s2 == null ? (s1 == null ? nf.Block(pos) : nf.Block(pos, s1))
: (s1 == null ? nf.Block(pos, s2) : nf.Block(pos, s1, s2));
X10ClassType resultType = (X10ClassType) thisType.asType();
// for Generic classes
final List<ParameterType> typeParams = thisType.typeParameters();
if (!typeParams.isEmpty()) {
List<Type> typeArgs = new ArrayList<Type>(typeParams);
resultType = (X10ClassType) resultType.typeArguments(typeArgs);
}
// no need to bind properties because the return type is HasType i.e., <: BlaBla
X10CanonicalTypeNode returnType = (X10CanonicalTypeNode) xnf.CanonicalTypeNode(pos, resultType);
DepParameterExpr guard = classInvariant();
if (guard!=null) {
// we gather the property names so we can convert all the this.p in the invariant to locals for the default ctor
//class A1(i:Int) {this.i==2} {
// def this() { property(2); }
//}
//class B1(b:Int) {this.i!=3} extends A1 {}
final HashSet<Name> propNames = new HashSet<Name>();
for (PropertyDecl p : properties)
propNames.add(p.name().id());
// replace "this" in the invariant with no qualifiers for the guard
class CannotConvertInvariantToGuard extends RuntimeException {}
try {
guard = (DepParameterExpr) guard.visit(new NodeVisitor() {
@Override
public Node override(Node n) {
if (n instanceof Call)
throw new CannotConvertInvariantToGuard();
if (!(n instanceof Field)) return null;
Field f = (Field) n;
if (!(f.target() instanceof X10Special)) return null;
// This is not a good test cause you can refer to a super property with "this".
// ((X10Special) f.target()).kind()==Special.Kind.THIS)
if (propNames.contains(f.name().id()))
return nf.Local(n.position(),f.name());
throw new CannotConvertInvariantToGuard();
}
});
} catch (CannotConvertInvariantToGuard e) {
guard = null;
Errors.issue(ts.extensionInfo(), new SemanticException("Cannot create the default constructor because the class invariant uses property methods, self, or super. Please define a constructor explicitly."), classInvariant.position());
}
}
ConstructorDecl cd = xnf.X10ConstructorDecl(pos,
nf.FlagsNode(pos, Flags.PUBLIC),
nf.Id(pos, TypeSystem.CONSTRUCTOR_NAME),
nf.HasType(returnType),
typeFormals,
formals,
guard,
null, // offerType
Collections.<TypeNode>emptyList(),
block);
return cd;
}
public String toString() {
StringBuilder sb = new StringBuilder();
Flags flags = this.flags.flags();
sb.append(flags.clearInterface().translate());
sb.append(flags.isInterface() ? "interface " : "class ");
sb.append(name);
if (!typeParameters.isEmpty()) {
sb.append("[");
boolean first = true;
for (TypeParamNode p : typeParameters) {
if (!first) sb.append(",");
first = false;
sb.append(p);
}
sb.append("]");
}
if (!properties.isEmpty()) {
sb.append("(");
boolean first = true;
for (PropertyDecl p : properties) {
if (!first) sb.append(",");
first = false;
sb.append(p);
}
sb.append(")");
}
if (classInvariant != null) {
sb.append("{");
sb.append(classInvariant);
sb.append("}");
}
sb.append(" ");
sb.append(body);
return sb.toString();
}
@Override
public void prettyPrintHeader(CodeWriter w, PrettyPrinter tr) {
w.begin(0);
if (type != null) {
Flags flags = type.flags();
if (flags.isInterface()) {
w.write(flags.clearInterface().clearAbstract().translate());
}
else {
w.write(flags.translate());
}
if (flags.isInterface()) {
w.write("interface ");
}
else {
w.write("class ");
}
}
tr.print(this, name, w);
if (!typeParameters.isEmpty()) {
w.write("[");
w.begin(0);
for (Iterator<TypeParamNode> pi = typeParameters.iterator(); pi.hasNext(); ) {
TypeParamNode pn = pi.next();
print(pn, w, tr);
if (pi.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.end();
w.write("]");
}
if (!properties.isEmpty()) {
w.write("(");
w.begin(0);
for (Iterator<PropertyDecl> pi = properties.iterator(); pi.hasNext(); ) {
PropertyDecl pd = pi.next();
print(pd, w, tr);
if (pi.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.end();
w.write(")");
}
if (superClass() != null) {
w.allowBreak(0);
w.write("extends ");
print(superClass(), w, tr);
}
if (! interfaces.isEmpty()) {
w.allowBreak(2);
if (type != null) {
if (type.flags().isInterface()) {
w.write("extends ");
}
else {
w.write("implements ");
}
}
w.begin(0);
for (Iterator<TypeNode> i = interfaces().iterator(); i.hasNext(); ) {
TypeNode tn = (TypeNode) i.next();
print(tn, w, tr);
if (i.hasNext()) {
w.write(",");
w.allowBreak(0);
}
}
w.end();
}
w.unifiedBreak(0);
w.end();
w.write("{");
}
public List<Def> defs() {
return Collections.<Def>singletonList(type);
}
public MemberDef memberDef() {
return type;
}
public FlagsNode flags() {
return this.flags;
}
public Id name() {
return this.name;
}
public TypeNode superClass() {
return this.superClass;
}
public List<TypeNode> interfaces() {
return this.interfaces;
}
public ClassBody body() {
return this.body;
}
protected X10ClassDecl_c reconstruct(FlagsNode flags, Id name, TypeNode superClass, List<TypeNode> interfaces, ClassBody body) {
if (flags != this.flags || name != this.name || superClass != this.superClass || ! CollectionUtil.allEqual(interfaces, this.interfaces) || body != this.body) {
X10ClassDecl_c n = (X10ClassDecl_c) copy();
n.flags = flags;
n.name = name;
n.superClass = superClass;
n.interfaces = TypedList.copyAndCheck(interfaces, TypeNode.class, true);
n.body = body;
return n;
}
return this;
}
public Node visitChildren(NodeVisitor v) {
X10ClassDecl_c n = (X10ClassDecl_c) visitSignature(v);
ClassBody body = (ClassBody) n.visitChild(n.body, v);
return body == n.body ? n : n.body(body);
}
public Node buildTypesOverride(TypeBuilder tb) {
X10ClassDecl_c n = this;
n = n.preBuildTypes(tb);
n = n.buildTypesBody(tb);
n = n.postBuildTypes(tb);
return n;
}
private X10ClassDecl_c buildTypesBody(TypeBuilder tb) {
X10ClassDecl_c n = this;
TypeBuilder tb2 = tb.pushClass(n.type);
ClassBody body = (ClassBody) n.visitChild(n.body, tb2);
n = (X10ClassDecl_c) n.body(body);
return n;
}
protected boolean defaultConstructorNeeded() {
if (flags.flags().isInterface()) {
return false;
}
for (ClassMember cm : body().members()) {
if (cm instanceof ConstructorDecl) {
return false;
}
}
return true;
}
public Node typeCheckSupers(ContextVisitor tc, TypeChecker childtc) {
X10ClassDecl_c n = this;
// ### This should be done somewhere else, but before entering the body.
Context c = tc.context();
type.inStaticContext(c.inStaticContext());
FlagsNode flags = n.flags;
Id name = n.name;
TypeNode superClass = n.superClass;
List<TypeNode> interfaces = n.interfaces;
ClassBody body = n.body;
flags = (FlagsNode) visitChild(n.flags, childtc);
name = (Id) visitChild(n.name, childtc);
superClass = (TypeNode) n.visitChild(n.superClass, childtc);
interfaces = n.visitList(n.interfaces, childtc);
if (n.superClass() != null) {
if (type.superType() != n.superClass().typeRef())
throw new InternalCompilerError(n.position(), "ClassDecl_c.typeCheckSupers: unexpected super type " +n.superClass().typeRef()+ " doesn't equal " +type.superType());
assert type.superType() == n.superClass().typeRef();
}
n = (X10ClassDecl_c) n.reconstruct(flags, name, superClass, interfaces, body);
try {
n.checkSupertypeCycles(tc.typeSystem());
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
if (superClass != null) {
try {
Types.checkMissingParameters(superClass);
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
}
for (TypeNode itn : interfaces) {
try {
Types.checkMissingParameters(itn);
} catch (SemanticException e) {
Errors.issue(tc.job(), e, this);
}
}
return n;
}
public Node typeCheckBody(Node parent, ContextVisitor tc, TypeChecker childtc) {
X10ClassDecl_c old = this;
X10ClassDecl_c n = this;
FlagsNode flags = n.flags;
Id name = n.name;
TypeNode superClass = n.superClass;
List<TypeNode> interfaces = n.interfaces;
ClassBody body = n.body;
body = (ClassBody) n.visitChild(body, childtc);
n = (X10ClassDecl_c) n.reconstruct(flags, name, superClass, interfaces, body);
n = (X10ClassDecl_c) tc.leave(parent, old, n, childtc);
return n;
}
public void prettyPrintFooter(CodeWriter w, PrettyPrinter tr) {
w.write("}");
w.newline(0);
}
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
prettyPrintHeader(w, tr);
print(body(), w, tr);
prettyPrintFooter(w, tr);
}
public void dump(CodeWriter w) {
super.dump(w);
w.allowBreak(4, " ");
w.begin(0);
w.write("(name " + name + ")");
w.end();
if (type != null) {
w.allowBreak(4, " ");
w.begin(0);
w.write("(type " + type + ")");
w.end();
}
}
}