/* * 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.List; import polyglot.ast.ConstructorCall; import polyglot.ast.ConstructorCall_c; import polyglot.ast.Expr; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.TypeNode; import polyglot.types.ClassType; import polyglot.types.ConstructorDef; import polyglot.types.ConstructorInstance; import polyglot.types.Context; import polyglot.types.ErrorRef_c; import polyglot.types.QName; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.CollectionUtil; import polyglot.util.InternalCompilerError; import polyglot.util.Pair; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import polyglot.visit.TypeBuilder; import x10.errors.Errors; import x10.errors.Warnings; import x10.types.X10ConstructorDef; import x10.types.X10ConstructorInstance; import x10.types.X10ClassDef; import x10.types.X10ConstructorDef_c; import x10.types.constraints.CConstraint; /** * A call to this(...) or super(...) in the body of a constructor. * (The call new C(...) is represented by an X10New_c.) * @author vj * */ public class X10ConstructorCall_c extends ConstructorCall_c implements X10ConstructorCall { /** * @param pos * @param kind * @param qualifier * @param arguments */ public X10ConstructorCall_c(Position pos, Kind kind, Expr qualifier, List<TypeNode> typeArguments, List<Expr> arguments) { super(pos, kind, qualifier, arguments); this.typeArguments = typeArguments; } // Override to remove reference to ts.Object(), which will cause resolver loop. @Override public Node buildTypes(TypeBuilder tb) { TypeSystem ts = tb.typeSystem(); if (kind == THIS) { X10ConstructorDef cd = AssignPropertyCall_c.getConstructorDef(tb); if (cd != null) { cd.derivedReturnType(true); } } ConstructorCall_c n = this; ConstructorInstance ci = ts.createConstructorInstance(position(), position(), new ErrorRef_c<ConstructorDef>(ts, position(), "Cannot get ConstructorDef before type-checking constructor call.")); return n.constructorInstance(ci); } @Override public Node visitChildren(NodeVisitor v) { Expr qualifier = (Expr) visitChild(this.qualifier, v); Expr target = (Expr) visitChild(this.target, v); List<TypeNode> typeArguments = visitList(this.typeArguments, v); List<Expr> arguments = visitList(this.arguments, v); X10ConstructorCall_c n = (X10ConstructorCall_c) typeArguments(typeArguments); return n.reconstruct(qualifier, target, arguments); } List<TypeNode> typeArguments; public List<TypeNode> typeArguments() { return typeArguments; } public X10ConstructorCall typeArguments(List<TypeNode> args) { X10ConstructorCall_c n = (X10ConstructorCall_c) copy(); n.typeArguments = new ArrayList<TypeNode>(args); return n; } @Override public X10ConstructorCall qualifier(Expr qualifier) { return (X10ConstructorCall) super.qualifier(qualifier); } @Override public X10ConstructorCall kind(Kind kind) { return (X10ConstructorCall) super.kind(kind); } @Override public X10ConstructorCall arguments(List<Expr> arguments) { return (X10ConstructorCall) super.arguments(arguments); } @Override public X10ConstructorInstance constructorInstance() { return (X10ConstructorInstance) super.constructorInstance(); } @Override public X10ConstructorCall constructorInstance(ConstructorInstance ci) { return (X10ConstructorCall) super.constructorInstance(ci); } @Override public Node typeCheck(ContextVisitor tc) { X10ConstructorInstance ci; List<Expr> args; X10ConstructorCall_c n = this; TypeSystem ts = (TypeSystem) tc.typeSystem(); Context context = tc.context(); ClassType ct = context.currentClass(); Type superType = ct.superClass(); if (kind == SUPER && superType == null) { // this can happen for structs, and for Object Type type = context.currentClass(); // the super() call inserted by the parser needs to be thrown out NodeFactory nf = (NodeFactory) tc.nodeFactory(); return nf.Empty(Position.compilerGenerated(position())); } // The qualifier specifies the enclosing instance of this inner class. // The type of the qualifier must be the outer class of this // inner class or one of its super types. // // Example: // // class Outer { // class Inner { } // } // // class ChildOfInner extends Outer.Inner { // ChildOfInner() { (new Outer()).super(); } // } if (qualifier != null) { if (kind != SUPER) { Errors.issue(tc.job(), new Errors.CanOnlyQualifySuperConstructorInvocation(position())); } if (!superType.isClass() || !superType.toClass().isInnerClass() || superType.toClass().inStaticContext()) { Errors.issue(tc.job(), new Errors.ClassNotInnerClass(superType, position())); } Type qt = qualifier.type(); if (! qt.isClass() || !qt.isSubtype(superType.toClass().container(), context)) { Errors.issue(tc.job(), new Errors.QualifierDoesNotMatchEnclosingClass(qt, superType.toClass().container(), qualifier.position()), this); } } if (kind == SUPER) { if (! superType.isClass() && !ts.isUnknown(superType)) { Errors.issue(tc.job(), new Errors.SuperTypeIsNotAClass(ct, position())); } Expr q = qualifier; // If the super class is an inner class (i.e., has an enclosing // instance of its container class), then either a qualifier // must be provided, or ct must have an enclosing instance of the // super class's container class, or a subclass thereof. if (q == null && superType.isClass() && superType.toClass().isInnerClass()) { ClassType superContainer = (ClassType) superType.toClass().container(); // ct needs an enclosing instance of superContainer, // or a subclass of superContainer. ClassType e = ct; while (e != null) { if (e.isSubtype(superContainer, context) && ct.hasEnclosingInstance(e)) { NodeFactory nf = tc.nodeFactory(); q = nf.This(position(), nf.CanonicalTypeNode(position(), e)).type(e); break; } e = e.outer(); } if (e == null) { Errors.issue(tc.job(), new Errors.ClassTypeMustHaveEnclosingInstance(ct, superContainer, position())); } if (e == ct) { Errors.issue(tc.job(), new Errors.ClassTypeMustBeSpecifiedInSuperConstructor(ct, superContainer, position())); } } if (qualifier != q) n = (X10ConstructorCall_c) n.qualifier(q); } List<Type> argTypes = new ArrayList<Type>(); for ( Expr e : n.arguments()) { argTypes.add(e.type()); } if (kind == SUPER) { ct = ct.superClass().toClass(); } try { ci = (X10ConstructorInstance) ts.findConstructor(ct, ts.ConstructorMatcher(ct, argTypes, context)); args = n.arguments(); } catch (SemanticException e) { // Now, try to find the method with implicit conversions, making them explicit. try { Pair<ConstructorInstance,List<Expr>> p = X10New_c.tryImplicitConversions(n, tc, ct, argTypes); ci = (X10ConstructorInstance) p.fst(); args = p.snd(); } catch (SemanticException e2) { Pair<ConstructorInstance,List<Expr>> p = X10New_c.findConstructor(tc, n, ct, argTypes); ci = (X10ConstructorInstance) p.fst(); args = p.snd(); } } if (!ci.checkConstraintsAtRuntime()) { Warnings.checkErrorAndGuard(tc, ci, n); } n = (X10ConstructorCall_c) n.constructorInstance(ci); n = (X10ConstructorCall_c) n.arguments(args); if (n.kind().equals(ConstructorCall.SUPER)) { Context ctx = context; if (! (ctx.inCode()) || ! (ctx.currentCode() instanceof X10ConstructorDef)) { Errors.issue(tc.job(), new SemanticException("A call to super must occur only in the body of a constructor.", position())); } else { // The constructor *within which this super call happens*. X10ConstructorDef thisConstructor = (X10ConstructorDef) ctx.currentCode(); Type returnType = ci.returnType(); CConstraint c = Types.realX(returnType); thisConstructor.setSupType(returnType); // Also make this information available downstream within this constructor. // Need to do this here because the constructor may not have a property clause. CConstraint cc = ctx.currentConstraint(); cc.addIn(thisConstructor.thisVar(), c); ctx.setCurrentConstraint(cc); } } return n; } public static void checkSuperType(ContextVisitor tc, Type returnType, Position position) { Context context = tc.context(); X10ClassDef classDef = context.currentClassDef(); Type extendsType = Types.get(classDef.superType()); if (extendsType!=null && returnType!=null && !returnType.isSubtype(extendsType, context) ) { Errors.issue(tc.job(), new Errors.SuperCallCannotEstablishSuperType(returnType,extendsType, position)); } } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(qualifier != null ? qualifier + "." : ""); sb.append(kind); /* 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(); } /* (non-Javadoc) * @see polyglot.ast.ConstructorCall#target(polyglot.ast.Expr) */ @Override public X10ConstructorCall target(Expr target) { return (X10ConstructorCall) super.target(target); } public List<Type> throwTypes(TypeSystem ts) { List<Type> l = new ArrayList<Type>(); l.addAll(ci.throwTypes()); l.addAll(ts.uncheckedExceptions()); return l; } }