/** * Type-checks this method declaration. It first checks that if this method overrides a method of * a superclass then the return type is a subtype of that of the overridden method. Then it builds * a type-checker whose only variable in scope is {@code this} of type {@code clazz} and the * parameters of the method, and where return instructions of type {@code returnType} are allowed. * It then type-checks the body of the method in that type-checker. It finally checks that if this * method does not return {@code void}, then every execution path ends with a {@code return} * command. * * @param clazz the semantical type of the class where this method occurs */ @Override protected void typeCheckAux(ClassType clazz) { TypeChecker checker; ClassType superclass; MethodSignature overridden; Type rt = returnType.typeCheck(); // we build a type-checker which signals errors for the source code // of the class where this method is defined, // whose only variables in scope is this of type // clazz and the parameters of the method, and // where return instructions of type returnType are allowed checker = new TypeChecker(rt, clazz.getErrorMsg()); // the main method is the only <i>static</i> method, where there is no this variable if (!getSignature().getName().equals("main")) checker = checker.putVar("this", clazz); // we enrich the type-checker with the formal parameters checker = getFormals() != null ? getFormals().typeCheck(checker) : checker; TypeList pars = getFormals() != null ? getFormals().typeCheck() : null; // we check if this method overrides a method of some superclass superclass = clazz.getSuperclass(); if (superclass != null) { overridden = superclass.methodLookup(name, pars); if (overridden != null) // it does override a method of a superclass. We check // that its return type has been refined. We use the // canBeAssignedToSpecial method so that // void can be overridden into void if (!rt.canBeAssignedToSpecial(overridden.getReturnType())) error( checker, "illegal return type for overriding method \"" + name + "\". Was " + overridden.getReturnType()); } // we type-check the body of the method in the resulting type-checker getBody().typeCheck(checker); // we check that there is no dead-code in the body of the method boolean stopping = getBody().checkForDeadcode(); // we check that if the method does not return void then // every syntactical execution path in the method ends with // a return command (continue and break are forbidden in this position) if (rt != VoidType.INSTANCE && !stopping) error(checker, "missing return statement"); }
/** * Generates the Java bytecode corresponding to this Kitten bytecode. * * @param classGen the Java class generator to be used for this generation * @return the Java {@code checkcast intoType} bytecode for casts between reference types and a * type conversion bytecode such as {@code i2f} for conversions between numercial types */ @Override public InstructionList generateJavaBytecode(AbstractClassGenerator classGen) { if (intoType instanceof ReferenceType) // we use the instruction factory to simplify the addition of the type to the constant pool return new InstructionList( classGen .getFactory() .createCheckCast((org.apache.bcel.generic.ReferenceType) intoType.toBCEL())); else if (fromType == IntType.INSTANCE && intoType == FloatType.INSTANCE) return new InstructionList(new I2F()); else // it must be float into int return new InstructionList(new F2I()); }