private Node buildFieldDecl(FieldDecl fd) throws SemanticException { Type t = fd.declType(); if (t.isSubtype(SJ_PROTOCOL_TYPE)) { if (!(fd instanceof SJFieldProtocolDecl)) { throw new SemanticException( "[SJProtocolDeclTypeBuilder] Protocols may only be declared using the protocol keyword: " + fd); } SJTypeNode tn = disambiguateSJTypeNode(this, ((SJProtocolDecl) fd).sessionType()); SJSessionType st = tn.type(); String sjname = fd.name(); // Should match that given by SJVariable.sjname. SJFieldInstance fi = (SJFieldInstance) fd.fieldInstance(); SJFieldProtocolInstance fpi = sjts.SJFieldProtocolInstance((SJFieldInstance) fd.fieldInstance(), st, sjname); fpi.setConstantValue( fi .constantValue()); // Currently, constant checker not run on custom nodes/type // objects. (Previously done by SJNoAliasTypeBuilder.) fd = fd.fieldInstance(fpi); fd = (FieldDecl) setSJProtocolDeclExt((SJProtocolDecl) fd, tn, sjname); updateSJFieldInstance(fi, fpi); } return fd; }
@Override public Node leave(Node parent, Node old, Node n, NodeVisitor v) { // do context bookkeeping first if (old instanceof X10MethodDecl) { assert ((X10MethodDecl) old).returnType().type() == returnType.peek(); returnType.pop(); } // NB: for calls and closure calls, the rules for boxing are complicated, // so we insert a simple Cast AST node, so that codegen makes a decision // whether to do boxing/unboxing. The goal is to ensure, that // the only places, where codegen needs to consider boxing/unboxing // are: // * casts // * method or closure call arguments // Generic methods (return type T) can return boxed values (e.g., x10.core.UInt) // but in the type instantiated [UInt] subclass it is treated as unboxed int. // We need to insert explicit cast to // an unboxed type, so that proper conversion method call is inserted later. if (n instanceof X10Call && !(parent instanceof Eval)) { X10Call call = (X10Call) n; Receiver target = call.target(); MethodInstance mi = call.methodInstance(); Type expectedReturnType = call.type(); // do not insert cast the expected type is already boxed or is void if (X10PrettyPrinterVisitor.isBoxedType(expectedReturnType) || expectedReturnType.isVoid() // (void) never needs boxing // or if the method def type is void -- it is a synthetic method without a proper // definition || mi.def().returnType().get().isVoid()) return n; if (X10PrettyPrinterVisitor.isBoxedType(mi.def().returnType().get())) { // only insert cast if the actual returned type is boxed return cast(call, expectedReturnType); } } // Closures may be implemented by methods returning boxed or unboxed values, // depending on some involved condition that is checked in codegen. // So add the dummy type cast to give the codegen // chance to handle unboxing in a single place if (n instanceof ClosureCall && !(parent instanceof Eval) && !(parent instanceof Cast)) { ClosureCall call = (ClosureCall) n; // if the return type is not primitive, then unboxing will not be needed if (X10PrettyPrinterVisitor.isBoxedType(call.type()) || call.type().isVoid()) return n; return cast(call, call.type()); } if (n instanceof Expr) { // boxing may be needed only for expressions Expr expr = (Expr) n; // parent node still has "old" as its child if (isBoxed(expr) && expectsUnboxed(parent, old)) { return unbox(expr); } else if (isUnboxed(expr) && expectsBoxed(parent, old)) { return box(expr); } } return n; }
public boolean hasDeserializationConstructor(Context context) { for (ConstructorDef cd : constructors()) { if (cd.formalTypes().size() == 1) { Type type = cd.formalTypes().get(0).get(); if (type.isSubtype(type.typeSystem().Deserializer(), context)) { return true; } } } return false; }
/** * The ast nodes will use this callback to notify us that they throw an exception of type t. This * method will throw a SemanticException if the type t is not allowed to be thrown at this point; * the exception t will be added to the throwsSet of all exception checkers in the stack, up to * (and not including) the exception checker that catches the exception. * * @param t The type of exception that the node throws. * @throws SemanticException */ public void throwsException(Type t, Position pos) throws SemanticException { if (!t.isUncheckedException()) { // go through the stack of catches and see if the exception // is caught. boolean exceptionCaught = false; ExceptionChecker ec = this; while (!exceptionCaught && ec != null) { if (ec.catchable != null) { for (Iterator<Type> iter = ec.catchable.iterator(); iter.hasNext(); ) { Type catchType = (Type) iter.next(); if (ts.isSubtype(t, catchType, ts.emptyContext())) { exceptionCaught = true; break; } } } if (!exceptionCaught && ec.throwsSet != null) { // add t to ec's throwsSet. ec.throwsSet.add(t); } if (ec.catchAllThrowable) { // stop the propagation exceptionCaught = true; } ec = ec.pop(); } if (!exceptionCaught) { reportUncaughtException(t, pos); } } }
private static Map<String, Long> getMessageSVUID(Type messageType) throws SJIOException, ClassNotFoundException // SJCompilerUtils has a simpler version of this routine. { HashMap<String, Long> ours = new HashMap<String, Long>(); if (messageType instanceof SJSessionType) // Should come before ordinary class cases? (But SJSessionType shouldn't be a // class type). { ours.putAll(getClassSVUIDs((SJSessionType) messageType)); } else if (messageType.isPrimitive()) { // No SVUID needed for primitive types. } else if (messageType.isClass()) // Duplicated from above. { String className = messageType.toClass().fullName(); Class<?> c = Class.forName(className); if (c.isInterface()) { // Interfaces don't have SVUIDs (so what should we do here?). // This encourages use of // abstract classes rather than interfaces for message types? } else { ObjectStreamClass osc = ObjectStreamClass.lookup(c); if (osc == null) { throw new SJIOException("Class not serializable: " + c); } ours.put( className, osc .getSerialVersionUID()); // Not possible to find a different SVUID for the same // (name) class here? // SVUIDs could be recorded in the // session type objects. // Put currently problems working // with these values at compilation time if the class // binary is not available a priori (SVUID value not built // yet?). } } else if (messageType.isArray()) { throw new SJIOException("Array types not done yet: " + messageType); } return ours; }
private Node buildFormal(Formal f) throws SemanticException // Based on buildLocalDecl. { Type t = f.declType(); SJLocalInstance li = (SJLocalInstance) f.localInstance(); if (t.isSubtype(SJ_ABSTRACT_CHANNEL_TYPE)) { if (!(f instanceof SJFormal)) { throw new SemanticException( "[SJProtocolDeclTypeBuilder] Session socket parameters should be declared by their session type: " + f); } SJTypeNode tn = disambiguateSJTypeNode(this, ((SJFormal) f).sessionType()); SJSessionType st = tn.type(); String sjname = f.name(); // Should match that given by SJVariable.sjname. f = f.localInstance(sjts.SJLocalProtocolInstance(li, st, sjname)); f = setSJFormalExt((SJFormal) f, tn, sjname); } return f; }
private Node buildLocalDecl(LocalDecl ld) throws SemanticException { Type t = ld.declType(); SJLocalInstance li = (SJLocalInstance) ld.localInstance(); // SJNamedInstance ni = null; if (t.isSubtype(SJ_PROTOCOL_TYPE)) // Mostly the same as for LocalDecl. { if (!(ld instanceof SJLocalProtocolDecl)) { throw new SemanticException( "[SJProtocolDeclTypeBuilder] Protocols may only be declared using the protocol keyword: " + ld); } SJTypeNode tn = disambiguateSJTypeNode(this, ((SJProtocolDecl) ld).sessionType()); SJSessionType st = tn.type(); String sjname = ld.name(); // Should match that given by SJVariable.sjname. ld = ld.localInstance(sjts.SJLocalProtocolInstance(li, st, sjname)); ld = (LocalDecl) setSJProtocolDeclExt((SJProtocolDecl) ld, tn, sjname); } return ld; }
void uncaughtType(Type t, Position pos) throws SemanticException { SemanticException e = new SemanticException( codeType + " cannot throw a \"" + t + "\"; the exception must either be caught or declared to be thrown.", pos); Map<String, Object> map = CollectionFactory.newHashMap(); map.put(CodedErrorInfo.ERROR_CODE_KEY, CodedErrorInfo.ERROR_CODE_SURROUND_THROW); map.put("TYPE", t.toString()); e.setAttributes(map); throw e; }
/** Type check the statement. */ public Node typeCheck(TypeChecker tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); // Check that all initializers have the same type. // This should be enforced by the parser, but check again here, // just to be sure. Type t = null; for (Iterator i = inits.iterator(); i.hasNext(); ) { ForInit s = (ForInit) i.next(); if (s instanceof LocalDecl) { LocalDecl d = (LocalDecl) s; Type dt = d.type().type(); if (t == null) { t = dt; } else if (!t.equals(dt)) { throw new InternalCompilerError( "Local variable " + "declarations in a for loop initializer must all " + "be the same type, in this case " + t + ", not " + dt + ".", d.position()); } } } if (cond != null && !ts.isImplicitCastValid(cond.type(), ts.Boolean())) { throw new SemanticException( "The condition of a for statement must have boolean type.", cond.position()); } return this; }
@Override public boolean typeEquals(Type type1, Type type2) { // Removed the assert_ calls as this is a hotspot when using typecase return type1.typeEqualsImpl(type2); }
private Node translateExtendedFor(ExtendedFor n, List<String> labels) throws SemanticException { if (n.expr().type().isArray()) { return translateExtForArray(n, labels); } Position pos = Position.compilerGenerated(); Type iterType = ts.typeForName("java.util.Iterator"); Type iteratedType = n.decl().type().type(); // translate "L1,...,Ln: for (C x: e) b" to // "{ Iterator iter = e.iterator(); L1,...,Ln: while (iter.hasNext();) { C x = (C)iter.next(); // b }" // Create the iter declaration "Iterator iter = e.iterator()" Id iterName = freshName("iter"); LocalDecl iterDecl; LocalInstance iterLI = ts.localInstance(pos, Flags.NONE, iterType, iterName.id()); { Id id = nodeFactory().Id(pos, "iterator"); Call iterator = nodeFactory().Call(pos, n.expr(), id); iterator = (Call) iterator.type(iterType); iterator = iterator.methodInstance( ts.findMethod( n.expr().type().toClass(), "iterator", Collections.<Type>emptyList(), this.context().currentClass())); iterDecl = nodeFactory() .LocalDecl( pos, Flags.NONE, nodeFactory().CanonicalTypeNode(pos, iterType), iterName, iterator); iterDecl = iterDecl.localInstance(iterLI); } // create the loop body List<Stmt> loopBody = new ArrayList<Stmt>(); { Id id = nodeFactory().Id(pos, "next"); Call call = nodeFactory() .Call( pos, ((Local) nodeFactory().Local(pos, iterName).type(iterType)) .localInstance(iterDecl.localInstance()), id); call = (Call) call.type(ts.Object()); call = call.methodInstance( ts.findMethod( iterType.toClass(), "next", Collections.<Type>emptyList(), this.context().currentClass())); Cast cast = nodeFactory().Cast(pos, nodeFactory().CanonicalTypeNode(pos, iteratedType), call); cast = (Cast) cast.type(iteratedType); loopBody.add(n.decl().init(cast)); loopBody.add(n.body()); } // create the while loop While loop; { Id id = nodeFactory().Id(pos, "hasNext"); Call cond = nodeFactory() .Call( pos, ((Local) nodeFactory().Local(pos, iterName).type(iterType)) .localInstance(iterDecl.localInstance()), id); cond = (Call) cond.type(ts.Boolean()); cond = cond.methodInstance( ts.findMethod( iterType.toClass(), "hasNext", Collections.<Type>emptyList(), this.context().currentClass())); loop = nodeFactory().While(pos, cond, nodeFactory().Block(pos, loopBody)); } return nodeFactory().Block(pos, iterDecl, labelStmt(loop, labels)); }
public boolean callValid(Type thisType, List<Type> argTypes, Context context) { JL5TypeSystem ts = (JL5TypeSystem) typeSystem(); List<Type> l1 = this.formalTypes(); List<Type> l2 = argTypes; if ((l1.size() == 0) && (l2.size() != 0)) return false; Iterator<Type> itCallee = l1.iterator(); Iterator<Type> itCaller = l2.iterator(); // caller can either: // - have one argument less than callee (last argument of // callee is a varargs and caller do not provide a value) // - have same number of args. The last arg being either // - same type as the last arg of callee // - or same type as the last arg of callee which is a varargs array // - or an array of same type as the last arg of callee (which could be a varargs array) // - have more args, then: // - last args of callee must be a varargs array // - all extra args provided by the caller must match // the varargs array type of the callee. while (itCallee.hasNext() && itCaller.hasNext()) { Type t1 = itCallee.next(); Type t2 = itCaller.next(); // Varargs can be used only in the final argument position // When we reach the final argument, we check if it is varargs array. if (!itCallee.hasNext() && t1.isArray() && ((JL5ArrayType) t1).isVarargs()) { JL5ArrayType vartype = (JL5ArrayType) t1; // Every arguments remaining in the second iterator must match the type // of the varargs array if (!itCaller.hasNext()) { // if we also reached the last element of the caller, // check if the type matches or if it is an array return ts.isImplicitCastValid(t2, vartype, context) || ts.isImplicitCastValid(t2, vartype.base(), context); } else { // There are several arguments left, they should all match the callee's varargs array // type. while (itCaller.hasNext()) { // eat up actual args if (!ts.isImplicitCastValid(t2, vartype.base(), context)) { return false; } t2 = itCaller.next(); } } } else { if (!ts.isImplicitCastValid(t2, t1, context)) { return false; } } } // Caller provided less args than the callee has, which is legal // if callee is a variable arity method if (itCallee.hasNext() && isVariableArrity()) { itCallee.next(); } // and we've reached callee's last arg. return !(itCallee.hasNext() || itCaller.hasNext()); }