/* * 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.visit; import java.util.ArrayList; import java.util.List; import polyglot.ast.ClassBody; import polyglot.ast.ClassDecl; import polyglot.ast.ConstructorCall; import polyglot.ast.Expr; import polyglot.ast.Field; import polyglot.ast.Local; import polyglot.ast.New; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.TypeNode; import polyglot.frontend.Job; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.CodeDef; import polyglot.types.ConstructorDef; import polyglot.types.ConstructorInstance; import polyglot.types.Context; import polyglot.types.FieldDef; import polyglot.types.LocalInstance; import polyglot.types.MethodDef; import polyglot.types.Name; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.VarDef; import polyglot.types.VarInstance; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.util.SubtypeSet; import polyglot.visit.ContextVisitor; import polyglot.visit.InnerClassRemover; import polyglot.visit.LocalClassRemover; import polyglot.visit.NodeVisitor; import polyglot.visit.TypeBuilder; import x10.ast.TypeParamNode; import x10.ast.X10ClassDecl; import x10.ast.X10ConstructorDecl; import x10.ast.X10MethodDecl; import x10.ast.X10New; import x10.types.AsyncDef; import x10.types.AtDef; import x10.types.EnvironmentCapture; import x10.types.ParameterType; import x10.types.TypeParamSubst; import x10.types.X10ClassDef; import x10.types.X10ClassType; import x10.types.X10CodeDef; import x10.types.X10ConstructorInstance; import x10.types.X10MethodDef; import polyglot.types.TypeSystem; public class X10LocalClassRemover extends LocalClassRemover { /** * The type to be extended when translating an anonymous class that * implements an interface. */ //protected TypeNode defaultSuperType(Position pos) { // return null; //} protected class X10ConstructorCallRewriter extends ConstructorCallRewriter { public X10ConstructorCallRewriter(List<FieldDef> fields, ClassDef ct) { super(fields, ct); } public Node leave(Node old, Node n, NodeVisitor v) { Node n_ = super.leave(old, n, v); if (n_ instanceof X10New) { X10New neu = (X10New) n_; X10ConstructorInstance ci = (X10ConstructorInstance) neu.constructorInstance(); ConstructorDef nci = ci.def(); X10ClassType container = (X10ClassType) Types.get(nci.container()); if (container.def() == theLocalClass) { X10ClassType type = (X10ClassType) Types.baseType(neu.objectType().type()); List<Type> ta = type.typeArguments(); List<TypeNode> nta = neu.typeArguments(); assert (ta == null || ta.size() == nta.size()); List<ParameterType> params = type.x10Def().typeParameters(); if (!params.isEmpty() && (ta == null || ta.size() != params.size())) { assert (context().currentCode() instanceof X10MethodDef); X10MethodDef md = (X10MethodDef) context().currentCode(); if (ta == null) { ta = new ArrayList<Type>(); nta = new ArrayList<TypeNode>(); } else if (!md.typeParameters().isEmpty()) { ta = new ArrayList<Type>(ta); nta = new ArrayList<TypeNode>(nta); } ta.addAll(md.typeParameters()); for (Type pt : md.typeParameters()) { nta.add(nf.CanonicalTypeNode(neu.objectType().position(), pt)); } assert (ta.size() == nta.size()); assert (ta.size() == params.size()); } TypeParamSubst subst = new TypeParamSubst((TypeSystem) ts, ta, params); X10ConstructorInstance xci = (X10ConstructorInstance) subst.reinstantiate(ci); neu = neu.constructorInstance(xci); neu = neu.objectType(nf.CanonicalTypeNode(neu.objectType().position(), subst.reinstantiate(type))); neu = neu.typeArguments(nta); neu = (X10New) neu.type(subst.reinstantiate(neu.type())); // FIX:XTENLANG-949 (for mismatch between neu.argument and neu.ci.formalTypes) if (neu.arguments().size() > ci.formalTypes().size()) { assert (false) : "This should not happen"; List<Type> newFormalTypes = new ArrayList<Type>(); for (Expr arg : neu.arguments()) { newFormalTypes.add(arg.type()); } neu = neu.constructorInstance(ci.formalTypes(newFormalTypes)); } } return neu; } return n_; } } public X10LocalClassRemover(X10InnerClassRemover icrv) { super(icrv); } // [DC] Igor suggests that the purpose of this code is to fix the return type of the method // from which 1 or more local classes were removed. This is not possible during hte normal // course of the visitor, due to not knowing at this point what changes have actually occurred. // So do it here on the unwind as a sort of post pass. @Override protected Node leaveCall(Node old, Node n, NodeVisitor v) { Node res = super.leaveCall(old, n, v); if (res instanceof X10MethodDecl) { X10MethodDecl decl = (X10MethodDecl) res; Type rt = decl.returnType().type(); if (!rt.isClass()) return decl; X10ClassType type = (X10ClassType) Types.baseType(rt.toClass()); List<Type> ta = type.typeArguments(); List<ParameterType> params = type.x10Def().typeParameters(); if (!params.isEmpty() && (ta == null || ta.size() != params.size())) { X10MethodDef md = decl.methodDef(); if (ta == null) ta = new ArrayList<Type>(); for (int i = ta.size(); i < params.size(); i++) { ta.add(params.get(i)); } //ta.addAll(md.typeParameters()); assert (ta.size() == params.size()); } TypeParamSubst subst = new TypeParamSubst((TypeSystem) ts, ta, params); res = decl.returnType(decl.returnType().typeRef(Types.ref(subst.reinstantiate(rt)))); } return res; } @Override protected New adjustObjectType(New neu, ClassType ct) { X10New r = (X10New) super.adjustObjectType(neu, ct); assert (r.body() != null); Position pos = r.objectType().position(); List<Type> ta = ((X10ClassType) ct).typeArguments(); List<TypeNode> typeArgs = new ArrayList<TypeNode>(); if (ta != null) { for (Type t : ta) { typeArgs.add(nf.CanonicalTypeNode(pos, t)); } } r = r.typeArguments(typeArgs); return r; } @Override protected X10ConstructorInstance computeConstructorInstance(ConstructorDef cd) { ClassDef container = ((X10ClassType) Types.get(cd.container())).def(); return (X10ConstructorInstance) cd.asInstance().container(computeConstructedType(container, context().currentCode())); } @Override protected X10ClassType computeConstructedType(ClassDef cd, CodeDef currentCode) { X10ClassDef def = (X10ClassDef) cd; X10CodeDef md = (X10CodeDef) currentCode; X10ClassType t = ((X10ClassType)def.asType()).typeArguments(new ArrayList<Type>(md.typeParameters())); return t; } @Override protected X10ConstructorDecl addConstructor(ClassDecl cd, New neu, ConstructorInstance superCI) { X10ConstructorDecl res = (X10ConstructorDecl) super.addConstructor(cd, neu, superCI); Position pos = res.position(); Type rType = cd.classDef().asType(); rType = Types.instantiateTypeParametersExplicitly(rType); return res.returnType(nf.CanonicalTypeNode(pos, rType)); } /** * Rewrites the class L as follows: * <pre> * class X[A,B]{g} { * def m[C,D](){h} { * class L[E,F]{c} extends S[A,B,C,D,E,F] { * body * } * val v = new L[P,Q](); * } * } * </pre> * to * <pre> * class X[A,B]{g} { * class L'[E,F,C',D']{c[C'/C,D'/D]&&h[C'/C,D'/D]} extends S[A,B,C',D',E,F] { * body[C'/C,D'/D] * } * def m[C,D]() { * val v = new L[P,Q,C,D](); * } * } * </pre> */ @Override protected ClassDecl rewriteLocalClass(ClassDecl n, List<FieldDef> newFields) { assert (n instanceof X10ClassDecl && n.classDef().isMember()); X10ClassDecl cd = (X10ClassDecl) n; X10ClassDef def = cd.classDef(); X10ClassDef outer = (X10ClassDef) Types.get(def.outer()); X10CodeDef method = (X10CodeDef) context.currentCode(); assert outer != null; assert method != null; List<TypeParamNode> params = new ArrayList<TypeParamNode>(); List<ParameterType> typeParameters = new ArrayList<ParameterType>(); List<ParameterType.Variance> variances = new ArrayList<ParameterType.Variance>(); params.addAll(cd.typeParameters()); typeParameters.addAll(method.typeParameters()); for (ParameterType pt : method.typeParameters()) { // methods cannot have variant type parameters variances.add(ParameterType.Variance.INVARIANT); } // Warning: we reuse the original type parameters here to avoid rewriting all references to the anonymous type. // They may be renamed later on. List<ParameterType> origTypeParams = def.typeParameters(); for (int i = 0; i < typeParameters.size(); i++) { ParameterType p = typeParameters.get(i); ParameterType.Variance v = variances.get(i); NodeFactory xnf = (NodeFactory) nf; TypeParamNode pn = xnf.TypeParamNode(n.position(), xnf.Id(n.position(), p.name()), v).type(p); def.addTypeParameter(pn.type(), v); params.add(pn); } if (params.size() != cd.typeParameters().size()) { cd = cd.typeParameters(params); typeParameters.addAll(0, origTypeParams); TypeParamSubst subst = new TypeParamSubst((TypeSystem) ts, def.typeParameters(), typeParameters); def.superType(subst.reinstantiate(def.superType())); def.setInterfaces(subst.reinstantiate(def.interfaces())); cd = rewriteTypeParams(subst, cd); } n = cd.body((ClassBody) rewriteConstructorCalls(cd.body(), def, newFields)); return icrv.addFieldsToClass(n, newFields, ts, nf, false); } private X10ClassDecl rewriteTypeParams(final TypeParamSubst subst, X10ClassDecl cd) { return (X10ClassDecl) cd.visit(new NodeTransformingVisitor(job, ts, nf, new TypeParamSubstTransformer(subst)).context(context)); } protected NodeVisitor localBoxer() { return new X10LocalBoxer().context(context().freeze()); } protected class X10LocalBoxer extends LocalBoxer { public X10LocalBoxer() { } @Override protected Node leaveCall(Node old, Node n, NodeVisitor v) { Node r = super.leaveCall(old, n, v); if (n instanceof Local && r instanceof Field) { Local l = (Local) n; Field f = (Field) r; // walk the stack of enclosing capturing scopes Context c = context.findEnclosingCapturingScope(); while (c != null) { EnvironmentCapture ec = (EnvironmentCapture) c.currentCode(); List<VarInstance<? extends VarDef>> env = new ArrayList<VarInstance<? extends VarDef>>(ec.capturedEnvironment()); if (!env.contains(l.localInstance())) break; // replace local instance in capture with corresponding field and this instances env.remove(l.localInstance()); env.add(f.fieldInstance()); env.add(f.target().type().toClass().def().thisDef().asInstance()); ec.setCapturedEnvironment(env); c = c.pop().findEnclosingCapturingScope(); } } return r; } } @Override protected boolean isLocal(Context c, Name name) { CodeDef ci = c.definingCodeDef(name); if (ci == null) return false; while (c != null) { CodeDef curr = c.currentCode(); if (curr == ci) return true; // Allow closures, asyncs if (curr instanceof AsyncDef || curr instanceof AtDef) ; else { // FIX:XTENLANG-1159 return c.isValInScopeInClass(name); } c = c.pop(); } // FIX:XTENLANG-1159 return c.isValInScopeInClass(name); } @Override protected Node rewriteConstructorCalls(Node s, final ClassDef ct, final List<FieldDef> fields) { Node r = s.visit(new X10ConstructorCallRewriter(fields, ct)); return r; } }