/*
* 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.Iterator;
import java.util.List;
import polyglot.ast.Ambiguous;
import polyglot.ast.Call_c;
import polyglot.ast.Disamb;
import polyglot.ast.Expr;
import polyglot.ast.Id;
import polyglot.ast.Local;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Prefix;
import polyglot.ast.Receiver;
import polyglot.ast.Special;
import polyglot.ast.TypeNode;
import polyglot.ast.Precedence;
import polyglot.ast.Call;
import polyglot.ast.Term;
import polyglot.ast.ProcedureCall;
import polyglot.types.ClassDef;
import polyglot.types.ClassType;
import polyglot.types.ConstructorDef;
import polyglot.types.ConstructorInstance;
import polyglot.types.Def;
import polyglot.types.LazyRef;
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.Pair;
import polyglot.util.Position;
import polyglot.util.TypedList;
import polyglot.util.ErrorInfo;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import polyglot.visit.PrettyPrinter;
import polyglot.visit.TypeBuilder;
import polyglot.visit.CFGBuilder;
import polyglot.visit.ExceptionChecker;
import x10.constraint.XVar;
import x10.errors.Errors;
import x10.errors.Warnings;
import x10.errors.Errors.IllegalConstraint;
import x10.optimizations.inlining.Inliner;
import x10.types.ParameterType;
import x10.types.X10ClassType;
import x10.types.X10ConstructorInstance;
import polyglot.types.Context;
import x10.types.X10FieldInstance;
import x10.types.X10LocalInstance;
import x10.types.MethodInstance;
import x10.types.X10MethodDef;
import x10.types.X10ParsedClassType;
import x10.types.X10Use;
import polyglot.types.TypeSystem;
import polyglot.types.ProcedureDef;
import polyglot.types.ProcedureInstance;
import polyglot.types.MethodDef;
import polyglot.types.ErrorRef_c;
import polyglot.types.ContainerType;
import x10.types.checker.Checker;
import x10.types.checker.PlaceChecker;
import x10.types.constants.ConstantValue;
import x10.visit.X10TypeChecker;
import x10.X10CompilerOptions;
import x10.ExtensionInfo;
/**
* Representation of an X10 method call.
* @author Igor
* @author vj
*/
public class X10Call_c extends Call_c implements X10Call {
protected Receiver target;
protected Id name;
protected List<Expr> arguments;
protected MethodInstance mi;
protected boolean targetImplicit;
// TODO: implement Settable and decompose x.apply(i)
public X10Call_c(Position pos, Receiver target, Id name,
List<TypeNode> typeArguments, List<Expr> arguments) {
super(pos);
assert(name != null && arguments != null); // target may be null
this.target = target;
this.name = name;
this.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
this.targetImplicit = (target == null);
this.typeArguments = new ArrayList<TypeNode>(typeArguments);
}
/** Get the precedence of the call. */
public Precedence precedence() {
return Precedence.LITERAL;
}
/** Get the target object or type of the call. */
public Receiver target() {
return this.target;
}
/** Get the name of the call. */
public Id name() {
return this.name;
}
public MethodInstance procedureInstance() {
return methodInstance();
}
public Call procedureInstance(ProcedureInstance<? extends ProcedureDef> pi) {
return methodInstance((MethodInstance) pi);
}
public boolean isTargetImplicit() {
return this.targetImplicit;
}
/** Get the actual arguments of the call. */
public List<Expr> arguments() {
return this.arguments;
}
/** Reconstruct the call. */
protected X10Call_c reconstruct(Receiver target, Id name, List<Expr> arguments) {
if (target != this.target || name != this.name || ! CollectionUtil.allEqual(arguments,
this.arguments)) {
X10Call_c n = (X10Call_c) copy();
// If the target changes, assume we want it to be an explicit target.
n.targetImplicit = n.targetImplicit && target == n.target;
n.target = target;
n.name = name;
n.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
return n;
}
return this;
}
public Node buildTypes(TypeBuilder tb) {
Call_c n = (Call_c) super.buildTypes(tb);
TypeSystem ts = tb.typeSystem();
MethodInstance mi = ts.createMethodInstance(position(),position(), new ErrorRef_c<MethodDef>(ts, position(), "Cannot get MethodDef before type-checking method invocation."));
return n.methodInstance(mi);
}
/**
* Used to find the missing static target of a static method call.
* Should return the container of the method instance.
*
*/
protected Type findContainer(TypeSystem ts, MethodInstance mi) {
return mi.container();
}
/** Dumps the AST. */
public void dump(CodeWriter w) {
super.dump(w);
w.allowBreak(4, " ");
w.begin(0);
w.write("(targetImplicit " + targetImplicit + ")");
w.end();
if ( mi != null ) {
w.allowBreak(4, " ");
w.begin(0);
w.write("(instance " + mi + ")");
w.end();
}
w.allowBreak(4, " ");
w.begin(0);
w.write("(name " + name + ")");
w.end();
w.allowBreak(4, " ");
w.begin(0);
w.write("(arguments " + arguments + ")");
w.end();
}
public Term firstChild() {
if (target instanceof Term) {
return (Term) target;
}
return listChild(arguments, null);
}
public <S> List<S> acceptCFG(CFGBuilder v, List<S> succs) {
if (target instanceof Term) {
Term t = (Term) target;
if (!arguments.isEmpty()) {
v.visitCFG(t, listChild(arguments, null), ENTRY);
v.visitCFGList(arguments, this, EXIT);
} else {
v.visitCFG(t, this, EXIT);
}
}
return succs;
}
/** Check exceptions thrown by the call. */
public Node exceptionCheck(ExceptionChecker ec) {
if (mi == null) {
throw new InternalCompilerError(position(),
"Null method instance after type "
+ "check.");
}
return super.exceptionCheck(ec);
}
// check that the implicit target setting is correct.
protected void checkConsistency(Context c) throws SemanticException {
if (targetImplicit) {
// the target is implicit. Check that the
// method found in the target type is the
// same as the method found in the context.
// as exception will be thrown if no appropriate method
// exists.
MethodInstance ctxtMI = c.findMethod(c.typeSystem().MethodMatcher(null, name.id(), mi.formalTypes(), c));
// cannot perform this check due to the context's findMethod returning a
// different method instance than the typeSystem in some situations
// if (!c.typeSystem().equals(ctxtMI, mi)) {
// throw new InternalCompilerError("Method call " + this + " has an " +
// "implicit target, but the name " + name + " resolves to " +
// ctxtMI + " in " + ctxtMI.container() + " instead of " + mi+ " in " + mi.container(), position());
// }
}
}
List<TypeNode> typeArguments;
public List<TypeNode> typeArguments() { return typeArguments; }
public X10Call typeArguments(List<TypeNode> args) {
if (args == this.typeArguments) return this;
X10Call_c n = (X10Call_c) copy();
n.typeArguments = new ArrayList<TypeNode>(args);
return n;
}
public X10Call target(Receiver target) {
X10Call_c n = (X10Call_c) copy();
n.target = target;
return n;
}
public X10Call name(Id name) {
X10Call_c n = (X10Call_c) copy();
n.name = name;
return n;
}
public X10Call targetImplicit(boolean targetImplicit) {
if (targetImplicit == this.targetImplicit) {
return this;
}
X10Call_c n = (X10Call_c) copy();
n.targetImplicit = targetImplicit;
return n;
}
public X10Call arguments(List<Expr> arguments) {
if (arguments == this.arguments) return this;
X10Call_c n = (X10Call_c) copy();
n.arguments = TypedList.copyAndCheck(arguments, Expr.class, true);
return n;
}
public MethodInstance methodInstance() {
return (MethodInstance) this.mi;
}
public X10Call methodInstance(MethodInstance mi) {
if (mi == this.mi) return this;
X10Call_c n = (X10Call_c) copy();
n.mi = mi;
return n;
}
@Override
public Node visitChildren(NodeVisitor v) {
Receiver target = (Receiver) visitChild(this.target, v);
Id name = (Id) visitChild(this.name, v);
List<TypeNode> typeArguments = visitList(this.typeArguments, v);
List<Expr> arguments = visitList(this.arguments, v);
X10Call_c n = (X10Call_c) typeArguments(typeArguments);
return n.reconstruct(target, name, arguments);
}
@Override
public Node disambiguate(ContextVisitor tc) {
return this;
}
private Type resolveType(ContextVisitor tc, Position pos, Receiver r, Name name) {
NodeFactory nf = (NodeFactory) tc.nodeFactory();
TypeSystem ts = (TypeSystem) tc.typeSystem();
TypeNode otn;
List<TypeNode> typeArgs = typeArguments();
Id nameNode = nf.Id(pos, name);
LazyRef<? extends Type> tRef = Types.lazyRef(ts.unknownType(pos));
if (typeArgs.size() > 0) {
otn = nf.AmbMacroTypeNode(pos, r, nameNode, typeArgs, Collections.<Expr>emptyList()).typeRef(tRef);
} else {
otn = nf.AmbTypeNode(pos, r, nameNode).typeRef(tRef);
}
TypeNode tn = disambiguateTypeNode(tc, (Ambiguous) otn, pos, r, nameNode);
if (tn == null)
return null;
Type t = tn.type();
// FIXME: why should these be different?
if (typeArgs.size() > 0) {
return ambMacroTypeNodeType(tc, t, typeArgs);
} else {
return ambTypeNodeType(tc, t);
}
}
private static Type ambTypeNodeType(ContextVisitor tc, Type t) {
Context c = (Context) tc.context();
TypeSystem ts = (TypeSystem) tc.typeSystem();
t = ts.expandMacros(t);
if (t instanceof ParameterType) {
ParameterType pt = (ParameterType) t;
Def def = Types.get(pt.def());
boolean inConstructor = false;
if (c.currentCode() instanceof ConstructorDef) {
ConstructorDef td = (ConstructorDef) c.currentCode();
Type container = Types.get(td.container());
if (container instanceof X10ClassType) {
X10ClassType ct = (X10ClassType) container;
if (ct.def() == def) {
inConstructor = true;
}
}
}
if (c.inStaticContext() && def instanceof ClassDef && ! inConstructor) {
return null;
}
}
try {
X10CanonicalTypeNode_c.checkType(tc.context(), t, Position.COMPILER_GENERATED);
} catch (SemanticException e) {
return null;
}
if (t.isClass()) {
ClassType ct = t.toClass();
if (ct.isTopLevel() || ct.isMember()) {
if (!ts.classAccessible(ct.def(), c)) {
return null;
}
}
}
return t;
}
private static Type ambMacroTypeNodeType(ContextVisitor tc, Type t, List<TypeNode> typeArgs) {
TypeSystem xts = (TypeSystem) tc.typeSystem();
if (xts.isUnknown(t)) {
return null;
}
if (!typeArgs.isEmpty() && t instanceof X10ParsedClassType) {
X10ParsedClassType ct = (X10ParsedClassType) t;
int numParams = ct.x10Def().typeParameters().size();
if (numParams != typeArgs.size())
return null;
List<Type> typeArgsTypes = new ArrayList<Type>(numParams);
for (TypeNode tni : typeArgs) {
typeArgsTypes.add(tni.type());
}
return ct.typeArguments(typeArgsTypes);
}
return t;
}
private static TypeNode disambiguateTypeNode(ContextVisitor tc,
Ambiguous otn, Position pos, Prefix prefix, Id name) {
TypeNode tn = null;
try {
// Look for a simply-named type.
Disamb disamb = tc.nodeFactory().disamb();
Node n = disamb.disambiguate(otn, tc, pos, prefix, name);
if (n instanceof TypeNode)
tn = (TypeNode) n;
} catch (SemanticException e) { }
return tn;
}
/**
* First try for a struct constructor, and then look for a static method.
* @param tc
* @param typeArgs
* @param argTypes
* @param args
* @return
*/
protected X10New findStructConstructor(ContextVisitor tc, Receiver r, List<Type> typeArgs, List<Type> argTypes, List<Expr> args) {
NodeFactory nf = (NodeFactory) tc.nodeFactory();
Type t = resolveType(tc, position(), r, name().id());
if (t == null)
return null;
if (Types.isX10Struct(t)) {
X10New_c neu = (X10New_c) nf.X10New(position(), nf.CanonicalTypeNode(position(), t), Collections.<TypeNode>emptyList(), args);
neu = (X10New_c) neu.newOmitted(true);
Pair<ConstructorInstance, List<Expr>> p = X10New_c.findConstructor(tc, neu, t, argTypes);
X10ConstructorInstance ci = (X10ConstructorInstance) p.fst();
if (ci.error() != null)
return null;
neu = (X10New_c) neu.typeCheck(tc);
ci = neu.constructorInstance();
if (ci.error() == null)
return neu;
}
return null;
}
private Receiver computeReceiver(ContextVisitor tc, MethodInstance mi) {
TypeSystem xts = (TypeSystem) tc.typeSystem();
NodeFactory nf = tc.nodeFactory();
Context c = (Context) tc.context();
Position prefixPos = position().startOf().markCompilerGenerated();
try {
if (mi.flags().isStatic() || c.inStaticContext()) {
Type container = findContainer(xts, mi);
return nf.CanonicalTypeNode(prefixPos, container).typeRef(Types.ref(container));
} else {
// The method is non-static, so we must prepend with "this", but we
// need to determine if the "this" should be qualified. Get the
// enclosing class which brought the method into scope. This is
// different from mi.container(). mi.container() returns a super type
// of the class we want.
if (mi.error() != null) {
// The method wasn't found -- assume current class.
return (Special) nf.This(prefixPos).del().typeCheck(tc);
}
Type scope = c.findMethodScope(name.id());
if (!xts.typeEquals(scope, c.currentClass(), c)) {
XVar thisVar = getThis(scope);
if (thisVar != null)
scope = Types.setSelfVar(scope, thisVar);
return (Special) nf.This(prefixPos,
nf.CanonicalTypeNode(prefixPos, scope)).del().typeCheck(tc);
}
else {
return (Special) nf.This(prefixPos).del().typeCheck(tc);
}
}
} catch (SemanticException e) {
throw new InternalCompilerError("Unexpected error while computing receiver", position(), e);
}
}
XVar getThis(Type t) {
t = Types.baseType(t);
if (t instanceof X10ClassType) {
return ((X10ClassType) t).x10Def().thisVar();
}
return null;
}
public Node typeCheck(ContextVisitor tc) {
NodeFactory xnf = (NodeFactory) tc.nodeFactory();
TypeSystem xts = (TypeSystem) tc.typeSystem();
Context c = (Context) tc.context();
if (mi != null && ((MethodInstance)mi).isValid()) // already typechecked
return this;
Name name = this.name().id();
Expr cc = null;
{
// Check if target.name is a field or local of function type;
// if so, convert to a closure call.
NodeFactory nf = (NodeFactory) tc.nodeFactory();
Expr e = null;
if (target() == null) {
final X10LocalInstance li = X10Local_c.findAppropriateLocal(tc, name);
if (li.error() == null) {
//e = xnf.Local(name().position(), name()).localInstance(li).type(li.type());
e = xnf.Local(name().position(), name()).localInstance(li);
e = (Expr) e.del().typeCheck(tc);
e = (Expr) e.del().checkConstants(tc);
}
}
if (e == null) {
boolean isStatic = target() instanceof TypeNode || (target() == null && c.inStaticContext());
X10FieldInstance fi = null;
if (target() == null) {
fi = (X10FieldInstance) c.findVariableSilent(name); // we didn't find a local, so it must be a field
if (fi != null && isStatic && !fi.flags().isStatic())
fi = null;
// it might be a field of an outer class, so we must check all inner classes in between are non-static
if (fi!=null && !fi.flags().isStatic()) {
X10ClassType containerType = (X10ClassType) fi.container();
X10ClassType currentClass = c.currentClass();
while (containerType.def()!=currentClass.def()) {
if (currentClass.flags().isStatic()) {
fi = null;
break;
}
currentClass = (X10ClassType) currentClass.outer();
if (currentClass==null) break;
}
}
}
if (fi == null) {
Type targetType = target() == null ? c.currentClass() : target().type();
fi = X10Field_c.findAppropriateField(tc, targetType, name,
isStatic, Types.contextKnowsType(target()), this.name().position());
}
if (fi.error() == null) {
Receiver target = this.target() == null ?
X10Disamb_c.makeMissingFieldTarget(fi, name().position(), tc) :
this.target();
//e = xnf.Field(new Position(target.position(), name().position()), target,
// name()).fieldInstance(fi).targetImplicit(target()==null).type(fi.type());
e = xnf.Field(new Position(target.position(), name().position()), target,
name()).fieldInstance(fi).targetImplicit(target()==null);
e = (Expr) e.del().typeCheck(tc);
e = (Expr) e.del().checkConstants(tc);
}
}
if (e != null) {
List<Type> typeArgs = new ArrayList<Type>(typeArguments().size());
for (TypeNode ti : typeArguments()) {
typeArgs.add(ti.type());
}
List<Type> actualTypes = new ArrayList<Type>(arguments().size());
for (Expr ei : arguments()) {
actualTypes.add(ei.type());
}
// First try to find the method without implicit conversions.
MethodInstance ci = Checker.findAppropriateMethod(tc, e.type(), ClosureCall.APPLY, typeArgs, actualTypes);
if (ci.error() != null) {
// Now, try to find the method with implicit conversions, making them explicit.
try {
Pair<MethodInstance,List<Expr>> p = Checker.tryImplicitConversions(this, tc, e.type(), ClosureCall.APPLY, typeArgs, actualTypes);
ci = p.fst();
}
catch (SemanticException se) { }
}
if (ci.error() != null) {
// Check for this case:
// val x = x();
if (e instanceof Local && xts.isUnknown(e.type())) {
Errors.issue(tc.job(),
new SemanticException("Possible closure call on uninitialized variable " + ((Local) e).name() + ".",
position()));
Node n = nf.ClosureCall(position(), e, typeArguments(), arguments()).closureInstance(ci);
//n = n.del().disambiguate(tc);
n = n.del().typeCheck(tc);
cc = (Expr) n;
}
} else {
Node n = nf.ClosureCall(position(), e, typeArguments(), arguments()).closureInstance(ci);
//n = n.del().disambiguate(tc);
n = n.del().typeCheck(tc);
cc = (Expr) n;
}
}
}
if (target instanceof TypeNode) {
Type t = ((TypeNode) target).type();
t = Types.baseType(t);
if (t instanceof ParameterType) {
Errors.issue(tc.job(),
new SemanticException("Cannot invoke a static method of a type parameter.",
position()));
}
}
List<Type> typeArgs = new ArrayList<Type>(this.typeArguments.size());
for (TypeNode tn : this.typeArguments) {
typeArgs.add(tn.type());
}
List<Type> argTypes = new ArrayList<Type>(this.arguments.size());
for (Expr e : this.arguments) {
Type et = e.type();
argTypes.add(et);
}
X10New structCall = null;
// Now trying a method call
Type targetType = this.target() == null ? null : this.target().type();
MethodInstance mi = null;
List<Expr> args = null;
// First try to find the method without implicit conversions.
Pair<MethodInstance, List<Expr>> p = Checker.findMethod(tc, this, targetType, name, typeArgs, argTypes);
mi = p.fst();
// [DC] surely p.snd() is the same as this.arguments() ???
args = p.snd();
SemanticException error=mi.error();
if (error != null && !(error instanceof Errors.MultipleMethodDefsMatch)) {
// Now, try to find the method with implicit conversions, making them explicit.
try {
p = Checker.tryImplicitConversions(this, tc, targetType, name, typeArgs, argTypes);
mi = p.fst();
args = p.snd();
}
catch (SemanticException e2) {
// Nothing worked. If you have a cc, thats the one. Exit with cc.
if (cc != null) {
// [IP] TODO: move closure call lookup here
Node result = cc.typeCheck(tc);
if (result instanceof Expr) {
try {
Types.checkMissingParameters((Expr) result);
} catch (SemanticException e) {
e.setPosition(this.position());
Errors.issue(tc.job(), e, this);
}
}
//Checker.checkOfferType(position(), ((ClosureCall) cc).closureInstance(), tc);
Warnings.checkErrorAndGuard(tc, (X10Use<?>) ((ProcedureCall) cc).procedureInstance(), result);
return result;
}
// Otherwise, try a struct constructor. If we have both a struct constructor and a
// closure call, then, according to spec section 8.2, the user can disambiguate
// using: "new StructCtor(...); therefore we give precedence to the closure-call.
// TODO: Need to try struct call with implicit conversions as well.
structCall = findStructConstructor(tc, target, typeArgs, argTypes, arguments);
}
}
if (mi.error() != null) {
// Must be a struct call
if (structCall != null) {
assert (this.target() == null || this.target() instanceof TypeNode);
try {
Checker.checkOfferType(position(), structCall.constructorInstance(), tc);
} catch (SemanticException e) {
e.setPosition(this.position());
Errors.issue(tc.job(), e, this);
}
Warnings.checkErrorAndGuard(tc, structCall.constructorInstance(), structCall);
return structCall;
}
// Nope, it wasn't -- so report the error and proceed
mi.error().setPosition(this.position());
Errors.issue(tc.job(), mi.error(), this);
}
// OK so now we have mi and args that correspond to a success.
// We have both a method and a struct constructor, so we give precedence to the method (the user can chose the struct ctor with "new")
// if the target is null, and thus implicit, find the target using the context
Receiver target = this.target() == null ? computeReceiver(tc, mi) : this.target();
if (target != null) {
/* This call is in a static context if and only if
* the target (possibly implicit) is a type node.
*/
boolean staticContext = (target instanceof TypeNode);
if (staticContext && !mi.flags().isStatic()) {
Errors.issue(tc.job(),
new Errors.CannotAccessNonStaticFromStaticContext(mi, position()));
}
// If the target is super, but the method is abstract, then complain.
if (target instanceof Special &&
((Special) target).kind() == Special.SUPER &&
mi.flags().isAbstract()) {
Errors.issue(tc.job(),
new SemanticException("Cannot call an abstract method of the super class",
this.position()));
}
}
Type rt = Checker.rightType(mi.rightType(), mi.x10Def(), target, c);
X10Call_c methodCall = (X10Call_c) this.methodInstance(mi);
methodCall = (X10Call_c) methodCall.arguments(args);
{
// check if this is a property call, and if so adjust the return type
if (mi.flags().isProperty()) {
if (c.inDepType()) {
// vj TODO: Why is this being repeated?
// rt = Checker.rightType(mi.rightType(), mi.x10Def(), target, c);
} else {
try {
rt = Checker.expandCall(mi.rightType(), methodCall, c);
} catch (IllegalConstraint z) {
// ignore, we will go with mi.rightType.
}
}
}
}
methodCall = (X10Call_c) methodCall.type(rt);
if (this.target() == null)
methodCall = (X10Call_c) methodCall.targetImplicit(true).target(target);
try {
Types.checkMissingParameters(methodCall);
} catch (SemanticException e) {
e.setPosition(this.position());
Errors.issue(tc.job(), e, this);
}
try {
Checker.checkOfferType(position(), (MethodInstance) methodCall.methodInstance(), tc);
} catch (SemanticException e) {
e.setPosition(this.position());
Errors.issue(tc.job(), e, this);
}
Warnings.checkErrorAndGuard(tc, mi, methodCall);
List<Type> ctcAnnotations = ((X10MethodDef) mi.def()).annotationsMatching(xts.CompileTimeConstant());
if (!ctcAnnotations.isEmpty()) {
X10CompilerOptions opts = (X10CompilerOptions) tc.job().extensionInfo().getOptions();
ConstantValue cv = Inliner.extractCompileTimeConstant(rt, ctcAnnotations, opts, c);
if (cv != null) {
methodCall = methodCall.constantValue(cv);
}
}
return methodCall;
}
ConstantValue constantValue;
public ConstantValue constantValue() { return constantValue; }
public boolean isConstant() { return constantValue != null; }
public X10Call_c constantValue(ConstantValue value) {
X10Call_c n = (X10Call_c) copy();
n.constantValue = value;
return n;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(targetImplicit ? "" : target.toString() + ".");
sb.append(name);
if (typeArguments != null && typeArguments.size() > 0) {
sb.append("[");
sb.append(CollectionUtil.listToString(typeArguments));
sb.append("]");
}
sb.append("(");
sb.append(CollectionUtil.listToString(arguments));
sb.append(")");
return sb.toString();
}
/** Write the expression to an output file. */
@Override
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
if (name.toString().startsWith("operator") && arguments.size() >= 2) {
w.begin(0);
print(arguments.get(0), w, tr);
w.write(name.toString().substring(8));
print(arguments.get(1), w, tr);
w.allowBreak(0, " ");
w.end();
return;
}
w.begin(0);
if (!targetImplicit) {
if (target instanceof Expr) {
printSubExpr((Expr) target, w, tr);
}
else if (target instanceof X10CanonicalTypeNode_c) {
((X10CanonicalTypeNode_c) target).prettyPrint(w, tr, false);
}
else if (target != null) {
print(target, w, tr);
}
w.write(".");
if (nonVirtual()) {
w.write("/"+"*"+"non-virtual"+"*"+"/");
}
w.allowBreak(2, 3, "", 0);
}
w.write(name + "");
if (typeArguments.size() > 0) {
w.write("[");
w.allowBreak(2, 2, "", 0); // miser mode
w.begin(0);
for (Iterator<TypeNode> i = typeArguments.iterator(); i.hasNext(); ) {
TypeNode t = i.next();
t.prettyPrint(w, tr);
if (i.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.write("]");
w.end();
}
w.write("(");
if (arguments.size() > 0) {
w.allowBreak(2, 2, "", 0); // miser mode
w.begin(0);
for (Iterator<Expr> i = arguments.iterator(); i.hasNext(); ) {
Expr e = i.next();
print(e, w, tr);
if (i.hasNext()) {
w.write(",");
w.allowBreak(0, " ");
}
}
w.end();
}
w.write(")");
w.end();
}
private boolean nonVirtual = false;
/* (non-Javadoc)
* @see polyglot.ast.Call#isNonVirtual()
*/
public boolean nonVirtual() {
return nonVirtual;
}
/* (non-Javadoc)
* @see polyglot.ast.Call#markNonVirtual()
*/
public X10Call nonVirtual(boolean nv) {
if (nonVirtual == nv) return this;
X10Call_c c = (X10Call_c) copy();
c.nonVirtual = nv;
return c;
}
public List<Type> throwTypes(TypeSystem ts) {
List<Type> l = new ArrayList<Type>();
assert mi != null : "null mi for " + this;
l.addAll(mi.throwTypes());
l.addAll(ts.uncheckedExceptions());
if (target instanceof Expr && ! (target instanceof Special)) {
l.add(ts.NullPointerException());
}
return l;
}
}