/* * 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 x10c.visit; import java.util.List; import polyglot.ast.Assign; import polyglot.ast.Call; import polyglot.ast.ConstructorCall; import polyglot.ast.Eval; import polyglot.ast.Expr; import polyglot.ast.FieldDecl; import polyglot.ast.LocalDecl; import polyglot.ast.New; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.NullLit; import polyglot.ast.Receiver; import polyglot.ast.Return; import polyglot.ast.TypeNode; import polyglot.frontend.Job; import polyglot.types.CodeDef; import polyglot.types.FunctionDef; import polyglot.types.FunctionInstance; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.util.InternalCompilerError; import polyglot.visit.ContextVisitor; import polyglot.visit.NodeVisitor; import x10.ast.ClosureCall; import x10.ast.SettableAssign; import x10.ast.X10Call; import x10.emitter.Emitter; import x10.types.MethodInstance; import x10.types.ParameterType; import x10.types.ParameterType.Variance; import x10.types.X10ClassType; import x10.types.X10ParsedClassType_c; import x10.types.constraints.SubtypeConstraint; import x10.types.constraints.TypeConstraint; import x10.visit.X10PrettyPrinterVisitor; // add cast node for java code generator public class JavaCaster extends ContextVisitor { private final TypeSystem xts; private final NodeFactory xnf; public JavaCaster(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (TypeSystem) ts; xnf = (NodeFactory) nf; } @Override protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { n = typeConstraintsCast(parent, old, n); n = railAccessCast(parent, n); n = typeBoundsReturnCast(parent, old, n); n = covReturnCast(parent, n); n = stringReturnCast(parent, n); if (X10PrettyPrinterVisitor.useSelfDispatch) { n = typeParamCast(parent, n); } return n; } private Node typeBoundsReturnCast(Node parent, Node old, Node n) throws SemanticException { if (n instanceof Return) { Return return1 = (Return) n; Expr e = return1.expr(); if (e == null) { return n; } if (!xts.isParameterType(e.type())) { return n; } CodeDef cd = context.currentCode(); if (cd instanceof FunctionDef) { FunctionDef fd = (FunctionDef) cd; Type expectedReturnType = ((FunctionInstance<?>) fd.asInstance()).returnType(); if (expectedReturnType.typeEquals(return1.expr().type(), context)) { return n; } Type rt = Types.baseType(return1.expr().type()); if (!expectedReturnType.typeEquals(rt, context)) { return return1.expr(cast(return1.expr(), expectedReturnType)); } } } return n; } private Node stringReturnCast(Node parent, Node n) throws SemanticException { if (n instanceof Return) { Return return1 = (Return) n; if (return1.expr() == null) { return n; } CodeDef cd = context.currentCode(); if (cd instanceof FunctionDef) { FunctionDef fd = (FunctionDef) cd; Type expectedReturnType = ((FunctionInstance<?>) fd.asInstance()).returnType(); if (expectedReturnType.typeEquals(return1.expr().type(), context)) { return n; } Type rt = Types.baseType(return1.expr().type()); if (rt.typeEquals(xts.String(), context) && !expectedReturnType.typeEquals(xts.String(), context)) { return return1.expr(cast(return1.expr(), expectedReturnType)); } } } return n; } private Node covReturnCast(Node parent, Node n) throws SemanticException { if (n instanceof Return) { Return return1 = (Return) n; if (return1.expr() == null) { return n; } CodeDef cd = context.currentCode(); if (cd instanceof FunctionDef) { FunctionDef fd = (FunctionDef) cd; Type expectedReturnType = ((FunctionInstance<?>) fd.asInstance()).returnType(); if (expectedReturnType.typeEquals(return1.expr().type(), context)) { return n; } Type rt = Types.baseType(return1.expr().type()); if (rt instanceof X10ClassType) { X10ClassType ct = (X10ClassType) rt; if (!ct.hasParams()) { return n; } List<Variance> variances = ct.x10Def().variances(); for (Variance v : variances) { if (v != ParameterType.Variance.INVARIANT) { return return1.expr(cast(return1.expr(), expectedReturnType)); } } } } } return n; } private Node typeParamCast(Node parent, Node n) throws SemanticException { if (n instanceof X10Call && !(parent instanceof Eval)) { X10Call call = (X10Call) n; Receiver target = call.target(); MethodInstance mi = call.methodInstance(); if (!(target instanceof TypeNode)) { Type bt = Types.baseType(target.type()); X10ClassType ct = null; if (bt instanceof X10ClassType) { ct = (X10ClassType) bt; } else if (xts.isParameterType(bt)) { ct = (X10ClassType) Types.baseType(mi.container()); } if (ct != null && (ct.typeArguments() != null && ct.typeArguments().size() > 0)) { if (isDispatch(ct, mi)) { return cast(call, call.type()); } else { Type rt = mi.def().returnType().get(); if (!xts.isParameterType(rt) && Emitter.containsTypeParam(rt)) { return cast(call, call.type()); } } } } } if (n instanceof ClosureCall && !(parent instanceof Eval)) { ClosureCall call = (ClosureCall) n; Receiver target = call.target(); MethodInstance mi = call.closureInstance(); if (!(target instanceof TypeNode)) { Type bt = Types.baseType(target.type()); if (bt instanceof X10ClassType) { X10ClassType ct = (X10ClassType) bt; if (ct.typeArguments() != null && ct.typeArguments().size() > 0) { if (isDispatch(ct, mi)) { return cast(call, call.type()); } else { Type rt = mi.def().returnType().get(); if (!xts.isParameterType(rt) && Emitter.containsTypeParam(rt)) { return cast(call, call.type()); } } } } } } return n; } private boolean isDispatch(X10ClassType bt, MethodInstance mi) { boolean isDispatch = false; if (bt.flags().isInterface() && !Emitter.isNativeRepedToJava(bt)) { List<Ref<? extends Type>> formalTypes = mi.def().formalTypes(); for (Ref<? extends Type> ref : formalTypes) { Type type = ref.get(); if (Emitter.containsTypeParam(type)) { isDispatch = true; break; } } } return isDispatch; } private Node railAccessCast(Node parent, Node n) throws SemanticException { if (n instanceof X10Call) { X10Call call = (X10Call) n; if (!xts.isParameterType(call.type())) { if (call.target() != null && (isIMC(call.target().type()))) { // e.g) val str = rail(0) = "str"; // -> val str = (String)(rail(0) = "str"); if (!(parent instanceof Eval)) { if (call.methodInstance().name() == SettableAssign.SET && !X10PrettyPrinterVisitor.isPrimitive(call.type())) { return cast(call, call.type()); } } } } } return n; } private boolean isIMC(Type type) { Type tbase = Types.baseType(type); return tbase instanceof X10ParsedClassType_c && ((X10ParsedClassType_c) tbase).def().asType().typeEquals(xts.IndexedMemoryChunk(), context); } // add casts for type constraints to type parameters // e.g) class C[T1,T2]{T1 <: T2} { def test(t1:T1):T2 {return t1;}} // -> class C[T1,T2]{T1 <: T2} { def test(t1:T1):T2 {return (T2) t1;}} private Node typeConstraintsCast(Node parent, Node old, Node n) throws SemanticException { if (!(old instanceof Expr)) { return n; } Expr e = (Expr) old; if (!xts.isParameterType(e.type())) { return n; } Type superType = null; TypeConstraint ctc = context.currentTypeConstraint(); List<SubtypeConstraint> terms = ctc.terms(); for (SubtypeConstraint sc : terms) { if (sc.isHaszero() || sc.isIsRef()) continue; if (sc.subtype().typeEquals(Types.baseType(e.type()), context) && sc.subtype() instanceof ParameterType) { superType = sc.supertype(); } } if (superType == null) { return n; } if (n instanceof NullLit) { return n; } Type toType = null; if (parent instanceof Call) { Call p = (Call) parent; for (int i = 0; i < p.arguments().size(); i++) { if (e == p.arguments().get(i)) { if (p.methodInstance().formalTypes().get(i) == superType) { toType = superType; break; } } } } else if (parent instanceof New) { New p = (New) parent; for (int i = 0; i < p.arguments().size(); i++) { if (e == p.arguments().get(i)) { if (p.constructorInstance().formalTypes().get(i) == superType) { toType = superType; break; } break; } } } else if (parent instanceof ConstructorCall) { ConstructorCall p = (ConstructorCall) parent; for (int i = 0; i < p.arguments().size(); i++) { if (e == p.arguments().get(i)) { if (p.constructorInstance().formalTypes().get(i) == superType) { toType = superType; break; } } } } else if (parent instanceof ClosureCall) { ClosureCall p = (ClosureCall) parent; for (int i = 0; i < p.arguments().size(); i++) { if (e == p.arguments().get(i)) { if (p.closureInstance().formalTypes().get(i) == superType) { toType = superType; break; } } } } else if (parent instanceof LocalDecl) { LocalDecl p = (LocalDecl) parent; if (e == p.init()) { if (p.localDef().asInstance().type() == superType) { toType = superType; } } } else if (parent instanceof FieldDecl) { FieldDecl p = (FieldDecl) parent; if (e == p.init()) { if (p.fieldDef().asInstance().type() == superType) { toType = superType; } } } else if (parent instanceof Assign) { Assign p = (Assign) parent; if (p.operator() == Assign.ASSIGN) { if (e == p.right()) { if (p.leftType() == superType) { toType = superType; } } } } if (toType != null) { return cast((Expr) n, toType); } return n; } private Expr cast(Expr n, Type toType) throws SemanticException { Expr e = xnf.X10Cast(n.position(), xnf.CanonicalTypeNode(n.position(), Types.baseType(toType)), n); return (Expr) e.del().disambiguate(this).typeCheck(this).checkConstants(this); } }