/* * 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.util; import java.util.ArrayList; import java.util.Collections; import java.util.List; import polyglot.ast.Block; import polyglot.ast.Formal; import polyglot.ast.NodeFactory; import polyglot.ast.TypeNode; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.Flags; import polyglot.types.LocalDef; import polyglot.types.Name; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.SystemResolver; import polyglot.types.Type; import polyglot.types.Types; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import x10.ast.AnnotationNode; import x10.ast.Closure; import x10.ast.ClosureCall; import x10.ast.X10Local_c; import x10.constraint.XLocal; import x10.constraint.XVar; import x10.types.ClosureDef; import x10.types.ClosureInstance; import x10.types.ClosureType; import x10.types.ClosureType_c; import x10.types.FunctionType_c; import x10.types.FunctionType; import x10.types.ParameterType; import x10.types.MethodInstance; import x10.types.X10LocalDef; import x10.types.ThisDef; import x10.types.X10ClassDef; import x10.types.X10ClassDef_c; import x10.types.X10ClassType; import polyglot.types.Context; import x10.types.X10MethodDef; import polyglot.types.TypeSystem; import x10.types.constraints.CConstraint; import x10.types.constraints.CLocal; import x10.types.matcher.Subst; import x10.extension.X10Ext; public class ClosureSynthesizer { /** Return an instance of the AST node, Closure, representing a closure (parms):retType => body. * This is treated as if it were defined by * new Fun_n_m * The type of this node is an anonymous class implementing the interface * * @param xts * @param xnf * @param pos * @param retType * @param parms * @param body * @param context * @return */ public static Closure makeClosure(TypeSystem xts, NodeFactory xnf, Position pos, Type retType, List<Formal> parms, Block body, Context context, List<X10ClassType> annotations) { List<Ref<? extends Type>> fTypes = new ArrayList<Ref<? extends Type>>(); List<LocalDef> fNames = new ArrayList<LocalDef>(); for (Formal f : parms) { fTypes.add(Types.ref(f.type().type())); fNames.add(f.localDef()); } ClosureDef cDef = xts.closureDef(pos, Types.ref(context.currentClass()), Types.ref(context.currentCode().asInstance()), Types.ref(retType), //Collections.EMPTY_LIST, fTypes, null, fNames, null, // Collections.<Ref<? extends Type>>emptyList(), null); if (null != annotations && !annotations.isEmpty()) { List<Ref<? extends Type>> ats = new ArrayList<Ref<? extends Type>>(); for (Type at : annotations) { ats.add(Types.ref(at)); } List<AnnotationNode> ans = new ArrayList<AnnotationNode>(); for (Type at : annotations) { ans.add(xnf.AnnotationNode(pos, xnf.CanonicalTypeNode(pos, at))); } } Closure closure = (Closure) xnf.Closure(pos, //Collections.EMPTY_LIST, parms, null, xnf.CanonicalTypeNode(pos, retType), body) .closureDef(cDef) .type(cDef.asType()); if (null != annotations && !annotations.isEmpty()) { List<AnnotationNode> ans = new ArrayList<AnnotationNode>(); for (Type at : annotations) { ans.add(xnf.AnnotationNode(pos, xnf.CanonicalTypeNode(pos, at))); } closure = (Closure) ((X10Ext) closure.ext()).annotations(ans); } return closure; } /** * Return the type of an anonymous class implementing a given closure * type, def. * @param xts * @param def * @return */ public static X10ClassDef closureAnonymousClassDef(final TypeSystem xts, final ClosureDef def) { final Position pos = def.position(); X10ClassDef cd = new X10ClassDef_c(xts, null) { private static final long serialVersionUID = 4543620040069882230L; @Override public boolean isFunction() { return true; } @Override public ClosureType asType() { if (asType == null) { X10ClassDef cd = this; asType = new ClosureType_c(xts, pos, def.errorPosition(), this, def.methodContainer().get()); } return (ClosureType) asType; } }; cd.position(pos); cd.errorPosition(def.errorPosition()); cd.name(null); cd.setPackage(null); cd.kind(ClassDef.ANONYMOUS); cd.outer(Types.ref(def.typeContainer().get().def())); cd.flags(Flags.FINAL); int numTypeParams = def.typeParameters().size(); int numValueParams = def.formalTypes().size(); ClosureType ct = (ClosureType) cd.asType(); ThisDef thisDef = cd.thisDef(); List<LocalDef> formalNames = xts.dummyLocalDefs(def.formalTypes()); X10MethodDef mi = xts.methodDef(pos, def.errorPosition(), Types.ref(ct), Flags.PUBLIC.Abstract(), def.returnType(), ClosureCall.APPLY, def.typeParameters(), def.formalTypes(), Collections.<Ref<? extends Type>>emptyList(), thisDef, def.formalNames(), def.guard(), def.typeGuard(), null, // FIXME: offerType null); cd.addMethod(mi); ClosureInstance ci = def.asInstance(); // Instantiate the super type on the new parameters. FunctionType sup = (FunctionType) closureBaseInterfaceDef(xts, numTypeParams, numValueParams, ci.returnType().isVoid(), def.formalNames(), def.guard()).asType(); // Compute type arguments. List<Type> typeArgs = new ArrayList<Type>(); List<LocalDef> fromNames = def.formalNames(); MethodInstance instance = sup.applyMethod(); List<LocalDef> toNames = ((X10MethodDef) instance.def()).formalNames(); XVar[] fromVars = Types.toVarArray(toNames); XVar[] toVars = Types.toVarArray(fromNames); List<Type> formalTypes = ci.formalTypes(); try { formalTypes = Subst.subst(formalTypes, fromVars, toVars); } catch (SemanticException e) { throw new InternalCompilerError("Unexpected exception while creating a closure type", pos, e); } typeArgs.addAll(formalTypes); Type rt = ci.returnType(); if (!rt.isVoid()) { try { rt = Subst.subst(rt, fromVars, toVars); } catch (SemanticException e) { throw new InternalCompilerError("Unexpected exception while creating a closure type", pos, e); } typeArgs.add(rt); } assert sup.x10Def().typeParameters().size() == typeArgs.size() : def + ", " + sup + ", " + typeArgs; sup = (FunctionType) sup.typeArguments(typeArgs); // todo: yoav added // Adding the method guard Ref<CConstraint> guard = def.guard(); if (guard != null) { CConstraint constraint = guard.get(); // need to rename the guard variables according to the method parameters try { constraint = Subst.subst(constraint, fromVars, toVars); } catch (SemanticException e) { throw new InternalCompilerError("Unexpected exception while creating a closure type", pos, e); } } cd.addInterface(Types.ref(sup)); return cd; } public static X10ClassDef closureBaseInterfaceDef(final TypeSystem xts, final int numTypeParams, final int numValueParams, final boolean isVoid) { return closureBaseInterfaceDef(xts, numTypeParams, numValueParams, isVoid, null, null); } /** * Synthetic generated interface for the function types. Mimics an X10 source level definition of * the following interface, where numTypeParams=m, and numValueParams=n. * * * package x10.lang; * public interface Fun_m_n extends Any ( * * public abstract def apply[X1,..,Xm,-Z1,..,-Zn,+U](formalNames){guard}:U; * or: * public abstract def apply[X1,..,Xm,-Z1,..,-Zn](formalNames){guard}:void; * } * * * @param numTypeParams * @param numValueParams * @param isVoid * @param formalNames * @param guard * @return */ public static X10ClassDef closureBaseInterfaceDef(final TypeSystem xts, final int numTypeParams, final int numValueParams, final boolean isVoid, List<LocalDef> formalNames1, // todo: the guard should not be included in the def final Ref<CConstraint> guard1) { final Position pos = Position.COMPILER_GENERATED; String name = "Fun_" + numTypeParams + "_" + numValueParams; if (isVoid) { name = "Void" + name; } // N.B. white space is needed to fix XTENLANG-1647 name = " " + name; // Check if the class has already been defined. QName fullName = QName.make("x10.lang", name); Type n = SystemResolver.first(xts.systemResolver().check(fullName)); if (guard1 == null && n instanceof X10ClassType) { X10ClassType ct = (X10ClassType) n; return ct.x10Def(); } X10ClassDef cd = (X10ClassDef) new X10ClassDef_c(xts, null) { private static final long serialVersionUID = -2035251841478824351L; @Override public boolean isFunction() { return true; } @Override public FunctionType asType() { if (asType == null) { X10ClassDef cd = this; asType = new FunctionType_c(xts, pos, pos, this); } return (FunctionType) asType; } }; cd.position(pos); cd.name(Name.make(name)); try { cd.setPackage(Types.ref(xts.packageForName(fullName.qualifier()))); } catch (SemanticException e) { assert false; } cd.kind(ClassDef.TOP_LEVEL); cd.superType(null); // interfaces have no superclass // Functions implement the Any interface. cd.setInterfaces(Collections.<Ref<? extends Type>> singletonList(Types.ref(xts.Any()))); cd.flags(Flags.PUBLIC.Abstract().Interface()); final List<ParameterType> typeParams = new ArrayList<ParameterType>(); final List<Ref<? extends Type>> argTypes = new ArrayList<Ref<? extends Type>>(); for (int i = 0; i < numTypeParams; i++) { ParameterType t = new ParameterType(xts, pos, pos, Name.make("X" + i), Types.ref(cd)); typeParams.add(t); } for (int i = 0; i < numValueParams; i++) { ParameterType t = new ParameterType(xts, pos, pos, Name.make("Z" + (i + 1)), Types.ref(cd)); argTypes.add(Types.ref(t)); cd.addTypeParameter(t, ParameterType.Variance.CONTRAVARIANT); } cd.setThisDef(xts.thisDef(pos, Types.ref(cd.asType()))); Type rt = null; if (!isVoid) { ParameterType returnType = new ParameterType(xts, pos, pos, Name.make("U"), Types.ref(cd)); cd.addTypeParameter(returnType, ParameterType.Variance.COVARIANT); rt = returnType; } else { rt = xts.Void(); } // NOTE: don't call cd.asType() until after the type parameters are // added. FunctionType ct = (FunctionType) cd.asType(); if (guard1 == null) { xts.systemResolver().install(fullName, ct); } ThisDef thisDef = cd.thisDef(); List<LocalDef> formalNames = xts.dummyLocalDefs(argTypes); CConstraint newGuard = Types.get(guard1); if (newGuard != null) { try { newGuard = Subst.subst(newGuard, Types.toVarArray(formalNames), Types.toVarArray(formalNames1)); } catch (SemanticException e) { throw new InternalCompilerError("Unexpected exception while creating a function type", pos, e); } } X10MethodDef mi = xts.methodDef(pos, pos, Types.ref(ct), Flags.PUBLIC.Abstract(), Types.ref(rt), ClosureCall.APPLY, typeParams, argTypes, Collections.<Ref<? extends Type>>emptyList(), thisDef, formalNames, Types.ref(newGuard), null, null, // offerType null); cd.addMethod(mi); return cd; } }