/* * 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.Iterator; import java.util.List; import java.util.ArrayList; import polyglot.ast.Expr; import polyglot.ast.Expr_c; import polyglot.ast.Node; import polyglot.ast.Precedence; import polyglot.ast.Term; import polyglot.ast.TypeNode; import polyglot.ast.NodeFactory; import polyglot.types.FieldInstance; import polyglot.types.Name; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.Types; import polyglot.util.CodeWriter; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; 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.Translator; import x10.constraint.XFailure; import x10.constraint.XLit; import x10.types.constraints.ConstraintManager; import x10.constraint.XVar; import x10.types.X10ClassType; import x10.types.checker.Converter; import polyglot.types.TypeSystem; import x10.types.constants.ConstantValue; import x10.types.constraints.CConstraint; import x10.types.constraints.CConstraint; import x10.errors.Errors; /** * An immutable representation of the list of elements in an X10 array constructor * new Array[T]{ e1,..., ek}. * * There is no surface syntax for a Tuple_c. Rather it is access */ public class Tuple_c extends Expr_c implements Tuple { protected List<Expr> elements; protected TypeNode indexType; public Tuple_c(Position pos, List<Expr> elements, TypeNode indexType) { super(pos); this.indexType = indexType; assert(elements != null); this.elements = TypedList.copyAndCheck(elements, Expr.class, true); } @Override public boolean isConstant() { return false; } @Override public ConstantValue constantValue() { return null; } @Override public Precedence precedence() { return Precedence.LITERAL; } /** Get the elements of the initializer. */ public List<Expr> arguments() { return this.elements; } /** Set the elements of the initializer. */ public Tuple arguments(List<Expr> elements) { Tuple_c n = (Tuple_c) copy(); n.elements = TypedList.copyAndCheck(elements, Expr.class, true); return n; } /** Reconstruct the initializer. */ protected Tuple_c reconstruct(TypeNode tn, List<Expr> elements) { if (tn!=indexType || ! CollectionUtil.allEqual(elements, this.elements)) { Tuple_c n = (Tuple_c) copy(); n.indexType = tn; n.elements = TypedList.copyAndCheck(elements, Expr.class, true); return n; } return this; } /** Visit the children of the initializer. */ public Node visitChildren(NodeVisitor v) { TypeNode tn = null; if (indexType!=null) tn = (TypeNode) visitChild( this.indexType, v ); List<Expr> elements = visitList(this.elements, v); return reconstruct(tn,elements); } public TypeNode indexType() { return indexType; } public Term firstChild() { return indexType!=null ? indexType : listChild(elements, null); } public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) { if (indexType!=null) { if (elements.size()>0) v.visitCFG(indexType, elements.get(0), ENTRY); else v.visitCFG(indexType, this, EXIT); } v.visitCFGList(elements, this, EXIT); return succs; } /** Type check the initializer. */ public Node typeCheck(ContextVisitor tc) { TypeSystem ts = (TypeSystem) tc.typeSystem(); Type type; Expr me = this; if (indexType == null) { type = null; for (Expr e : elements) { Type eType = e.type(); // Types.baseType(e.type()); if (type == null) { type = eType; } else { try { type = ts.leastCommonAncestor(type, eType, tc.context()); } catch (SemanticException z) { Errors.issue(tc.job(), z, this); type = ts.Any(); } } } if (type == null) { type = ts.Any(); // should be bottom type, not top } } else { type = indexType.type(); List<Expr> vals = arguments(); ArrayList<Expr> newChildren = new ArrayList<Expr>(); for (Expr e : vals) { Expr newE = Converter.attemptCoercion(tc, e, type); if (newE==null) { newE = e; Errors.issue(tc.job(), new Errors.ArrayLiteralTypeMismatch(e, type)); } newChildren.add(newE); } me = this.reconstruct(indexType,newChildren); } Type resultType = Types.makeArrayRailOf(type, elements.size(), position()); if (! Types.consistent(resultType)) Errors.issue(tc.job(), new Errors.InconsistentType(resultType, position())); return me.type(resultType); } @Override public String toString() { StringBuilder sb = new StringBuilder(); if (indexType!=null) { sb.append("new Array[").append(indexType).append("]"); } sb.append("["); for (Iterator<Expr> i = elements.iterator(); i.hasNext(); ) { Expr e = i.next(); sb.append(e.toString()); if (i.hasNext()) { sb.append(", "); } } sb.append("]"); return sb.toString(); } @Override public void prettyPrint(CodeWriter w, PrettyPrinter tr) { if (indexType!=null) { w.write("new Array["); printBlock(indexType, w, tr); w.write("]"); } w.write("{"); for (Iterator<Expr> i = elements.iterator(); i.hasNext(); ) { Expr e = i.next(); print(e, w, tr); if (i.hasNext()) { w.write(","); w.allowBreak(0, " "); } } w.write("}"); } @Override public void translate(CodeWriter w, Translator tr) { super.prettyPrint(w, tr); } }