/* * 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.util.ArrayList; import java.util.Collections; import java.util.List; import polyglot.ast.FlagsNode; import polyglot.ast.Formal; import polyglot.ast.Id; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.Term; import polyglot.ast.Term_c; import polyglot.ast.TypeNode; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.Flags; import polyglot.types.LazyRef; import polyglot.types.LocalDef; import polyglot.types.MemberDef; import polyglot.types.Package; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.Types; import polyglot.util.Position; import polyglot.util.TypedList; import polyglot.visit.CFGBuilder; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import polyglot.visit.TypeBuilder; import x10.constraint.XFailure; import x10.constraint.XVar; import x10.errors.Errors; import x10.extension.X10Del_c; import x10.types.ConstrainedType; import x10.types.MacroType; import x10.types.ParameterType; import x10.types.TypeDef; import x10.types.TypeDef_c; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10ParsedClassType; import polyglot.types.TypeSystem; import x10.types.constraints.CConstraint; import x10.types.constraints.CConstraint; import x10.types.constraints.ConstraintManager; import x10.types.constraints.TypeConstraint; public class TypeDecl_c extends Term_c implements TypeDecl { private TypeNode type; private DepParameterExpr guard; private List<Formal> formals; private List<TypeParamNode> typeParams; private Id name; private FlagsNode flags; private TypeDef typeDef; public TypeDecl_c(Position pos, FlagsNode flags, Id name, List<TypeParamNode> typeParameters, List<Formal> formals, DepParameterExpr guard, TypeNode type) { super(pos); this.flags = flags; this.name = name; this.typeParams = TypedList.copyAndCheck(typeParameters, TypeParamNode.class, true); this.formals = TypedList.copyAndCheck(formals, Formal.class, true); this.guard = guard; this.type = type; } public Id name() { return this.name; } public TypeDecl name(Id id) { TypeDecl_c n = (TypeDecl_c) copy(); n.name = id; return n; } public FlagsNode flags() { return this.flags; } public TypeDecl flags(FlagsNode flags) { TypeDecl_c n = (TypeDecl_c) copy(); n.flags = flags; return n; } public TypeNode type() { return this.type; } public TypeDecl type(TypeNode type) { TypeDecl_c n = (TypeDecl_c) copy(); n.type = type; return n; } public List<TypeParamNode> typeParameters() { return Collections.<TypeParamNode> unmodifiableList(this.typeParams); } public TypeDecl typeParameters(List<TypeParamNode> typeParams) { TypeDecl_c n = (TypeDecl_c) copy(); n.typeParams = TypedList.copyAndCheck(typeParams, TypeParamNode.class, true); return n; } public List<Formal> formals() { return Collections.<Formal> unmodifiableList(this.formals); } public TypeDecl formals(List<Formal> formals) { TypeDecl_c n = (TypeDecl_c) copy(); n.formals = TypedList.copyAndCheck(formals, Formal.class, true); return n; } public DepParameterExpr guard() { return guard; } public TypeDecl guard(DepParameterExpr guard) { TypeDecl_c n = (TypeDecl_c) copy(); n.guard = guard; return n; } /** Visit the children of the method. */ public Node visitChildren(NodeVisitor v) { Id id = (Id) this.visitChild(this.name, v); FlagsNode flags = (FlagsNode) this.visitChild(this.flags(), v); List<TypeParamNode> typeParams = this.visitList(this.typeParams, v); List<Formal> formals = this.visitList(this.formals, v); DepParameterExpr guard = (DepParameterExpr) this.visitChild(this.guard, v); TypeNode type = (TypeNode) this.visitChild(this.type, v); return reconstruct(flags, id, typeParams, formals, guard, type); } /** Visit the children of the method. */ public Node visitSignature(NodeVisitor v) { Id id = (Id) this.visitChild(this.name, v); FlagsNode flags = (FlagsNode) this.visitChild(this.flags(), v); List<TypeParamNode> typeParams = this.visitList(this.typeParams, v); List<Formal> formals = this.visitList(this.formals, v); DepParameterExpr guard = (DepParameterExpr) this.visitChild(this.guard, v); return reconstruct(flags, id, typeParams, formals, guard, this.type); } protected Node reconstruct(FlagsNode flags, Id name, List<TypeParamNode> typeParams, List<Formal> formals, DepParameterExpr guard, TypeNode type) { TypeDecl_c n = this; n = (TypeDecl_c) n.flags(flags); n = (TypeDecl_c) n.name(name); n = (TypeDecl_c) n.typeParameters(typeParams); n = (TypeDecl_c) n.formals(formals); n = (TypeDecl_c) n.guard(guard); n = (TypeDecl_c) n.type(type); return n; } public Context enterScope(Context c) { c = c.pushCode(typeDef); if (!c.inStaticContext() && typeDef.thisDef() != null) c.addVariable(typeDef.thisDef().asInstance()); return c; } public Context enterChildScope(Node child, Context c) { if (child != type) { // Push formals so they're in scope in the types of the other formals. c = c.pushBlock(); for (TypeParamNode f : typeParams) { f.addDecls(c); } for (Formal f : formals) { f.addDecls(c); } } else { if (guard != null) { // add the guard when descending into the RHS of the typedef Ref<CConstraint> vc = guard.valueConstraint(); Ref<TypeConstraint> tc = guard.typeConstraint(); if (vc != null || tc != null) { c = c.pushBlock(); c.setName(" Typedef guard for |" + name() + "| "); if (vc != null) c.addConstraint(vc); if (tc != null) { c.setTypeConstraintWithContextTerms(tc); } } } } return super.enterChildScope(child, c); } private static final boolean ALLOW_TOP_LEVEL_TYPEDEFS = true; @Override public Node buildTypesOverride(TypeBuilder tb) { final TypeSystem ts = (TypeSystem) tb.typeSystem(); NodeFactory nf = (NodeFactory) tb.nodeFactory(); X10ClassDef ct = (X10ClassDef) tb.currentClass(); Package package_ = tb.currentPackage(); boolean local = tb.inCode(); boolean topLevel = !local && ct == null; if (topLevel && !ALLOW_TOP_LEVEL_TYPEDEFS) { Errors.issue(tb.job(), new Errors.TypeDefinitionMustBeStaticClassOrInterfaceMembers(position())); } // FIXME: also check if the current method is static XVar thisVar = ct == null ? null : ct.thisVar(); Ref<X10ClassType> container = ct == null ? null : Types.ref(ct.asType()); Flags flags = local ? Flags.NONE : this.flags().flags(); if (topLevel) flags = flags.Static(); TypeDef typeDef = new TypeDef_c(ts, position(), name().position(), flags, name.id(), container, Collections.<ParameterType>emptyList(), thisVar, Collections.<LocalDef>emptyList(), Collections.<Ref<? extends Type>>emptyList(), null, null, null); if (!local && ct != null) { ct.addMemberType(typeDef); } typeDef.setPackage(package_ != null ? Types.ref(package_) : null); TypeDecl_c n = (TypeDecl_c) copy(); TypeBuilder tb2 = tb.pushDef(typeDef); n = (TypeDecl_c) n.visitSignature(tb2); n = (TypeDecl_c) X10Del_c.visitAnnotations(n, tb2); List<ParameterType> typeParameters = new ArrayList<ParameterType>(); for (TypeParamNode tpn : n.typeParameters()) { typeParameters.add(tpn.type()); } typeDef.setTypeParameters(typeParameters); List<Ref<? extends Type>> formalTypes = new ArrayList<Ref<? extends Type>>(); List<LocalDef> formalNames = new ArrayList<LocalDef>(); for (Formal f : n.formals()) { final Formal f2 = f; final LazyRef<CConstraint> cref = Types.<CConstraint>lazyRef(ConstraintManager.getConstraintSystem().makeCConstraint()); ConstrainedType t = ConstrainedType.xclause(f.type().typeRef(), cref); cref.setResolver(new Runnable() { public void run() { CConstraint c = ConstraintManager.getConstraintSystem().makeCConstraint(); c.addSelfBinding(ts.xtypeTranslator().translate(f2.localDef().asInstance())); cref.update(c); } }); formalTypes.add(f.type().typeRef()); formalNames.add(f.localDef()); } typeDef.setFormalTypes(formalTypes); typeDef.setFormalNames(formalNames); if (n.guard != null) { typeDef.setGuard(n.guard.valueConstraint()); typeDef.setTypeGuard(n.guard.typeConstraint()); } if (n.type != null) { TypeNode tn = (TypeNode) n.visitChild(n.type, tb2); n = (TypeDecl_c) n.type(tn); typeDef.setType(tn.typeRef()); } n = (TypeDecl_c) n.typeDef(typeDef); // Add to the system resolver. if (!local && typeDef.asType().isGloballyAccessible()) { if (ct == null) { if (ALLOW_TOP_LEVEL_TYPEDEFS) { QName pkgName = typeDef.package_() == null ? null : typeDef.package_().get().fullName(); ts.systemResolver().install(QName.make(pkgName, name.id()), typeDef.asType()); } } else { ts.systemResolver().install(QName.make(ct.fullName(), name.id()), typeDef.asType()); } } return n; } @Override public Node typeCheck(ContextVisitor tc) { try { checkCycles(type.type()); } catch (SemanticException z) { Errors.issue(tc.job(), z, this); } try { X10MethodDecl_c.dupFormalCheck(typeParams, formals); } catch (SemanticException z) { Errors.issue(tc.job(), z, this); } try { Types.checkMissingParameters(type); } catch (SemanticException e) { Errors.issue(tc.job(), e, type); } return this; } private void checkCycles(Type type) throws SemanticException { if (type instanceof MacroType) { MacroType mt = (MacroType) type; if (mt.def() == typeDef) { throw new Errors.RecursiveTypeDefinition(position()); } } if (type instanceof ConstrainedType) { ConstrainedType ct = (ConstrainedType) type; checkCycles(ct.baseType().get()); } if (type instanceof ClassType) { ClassType ct = (ClassType) type; checkCycles(ct.superClass()); for (Type t : ct.interfaces()) checkCycles(t); } } public TypeDef typeDef() { return typeDef; } public TypeDecl typeDef(TypeDef typeDef) { TypeDecl_c n = (TypeDecl_c) copy(); n.typeDef = typeDef; return n; } public Term firstChild() { return listChild(typeParameters(), listChild(formals(), type)); } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { List<Term> children = new ArrayList<Term>(); children.addAll(typeParams); children.addAll(formals); v.visitCFGList(children, type(), ENTRY); v.visitCFG(type(), this, EXIT); return succs; } public MemberDef memberDef() { return typeDef; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(flags().flags().translate()); sb.append("type "); sb.append(name()); if (typeParameters().size() > 0) { String sep = ""; sb.append("["); for (TypeParamNode f : typeParameters()) { sb.append(sep); sep = ","; sb.append(f); } sb.append("]"); } if (formals().size() > 0) { String sep = ""; sb.append("("); for (Formal f : formals()) { sb.append(sep); sep = ","; sb.append(f); } sb.append(")"); } if (guard() != null) { sb.append(guard()); } sb.append(" = "); sb.append(type()); sb.append(";"); return sb.toString(); } }