bool ValueNode::checkElementTypesRec (const DataTypePtr &dataType, LContext &lcontext, int &eIndex) const { // // recursively iterate through nested structs and arrays // in this data type, checking element types along the way // assert(eIndex < (int)elements.size()); if( StructTypePtr structType = dataType.cast<StructType>() ) { for(MemberVectorConstIterator it = structType->members().begin(); it != structType->members().end(); it++) { if(!checkElementTypesRec(it->type, lcontext, eIndex)) return false; } } else if( ArrayTypePtr arrayType = dataType.cast<ArrayType>() ) { for (int i = 0; i < arrayType->size(); ++i) { if( !checkElementTypesRec(arrayType->elementType(), lcontext, eIndex) ) return false; } } else if (!dataType->canCastFrom (elements[eIndex++]->type)) { string fromType = "unknown"; if( elements[eIndex-1]->type) fromType = elements[eIndex-1]->type->asString(); MESSAGE_LE (lcontext, ERR_ARR_EL_TYPE, elements[eIndex-1]->lineNumber, "Cannot convert the type of value element " << eIndex-1 << " " "(" << fromType << ") " "to type " << dataType->asString() << "."); return false; } return true; }
void CallNode::computeType (LContext &lcontext, const SymbolInfoPtr &initInfo) { // // Compute the type of a function call. This is the same type // as the function's return type, provided the call is valid. // // // Verify that what we are trying to call is actually a function. // if (!function) return; function->computeType (lcontext, initInfo); if (!function->type) return; FunctionTypePtr functionType = function->type.cast <FunctionType>(); if (!functionType) { MESSAGE_LE (lcontext, ERR_NON_FUNC, function->lineNumber, "Invalid function call to call non-function " "(" << function->name << " is of type " << function->type->asString() << ")."); return; } // // We shouldn't have more function call arguments than parameters. // const ParamVector ¶meters = functionType->parameters(); if (arguments.size() > parameters.size()) { MESSAGE_LE (lcontext, ERR_FUNC_ARG_NUM, function->lineNumber, "Too many arguments in call to function " << function->name << "."); return; } // // Compare the types of the arguments to the call with // the types of the function's parameters. // for (int i = 0; i < (int)parameters.size(); ++i) { if (i < (int)arguments.size()) { // // We have a function call argument for parameter i. // arguments[i]->computeType (lcontext, initInfo); TypePtr argType = arguments[i]->type; if (!argType) return; DataTypePtr paramType = parameters[i].type; if (parameters[i].isWritable()) { // // output parameter -- argument must be an lvalue // of the same type as the parameter // if (!arguments[i]->isLvalue (initInfo)) { MESSAGE_LE (lcontext, ERR_FUNC_ARG_LVAL, arguments[i]->lineNumber, "Argument " << i+1 << " in call to function " << function->name << " corresponds to an output " "parameter but it is not an lvalue."); return; } if (!paramType->isSameTypeAs (argType)) { MESSAGE_LE (lcontext, ERR_FUNC_ARG_TYPE, arguments[i]->lineNumber, "Type of argument " << i+1 << " in call to " "function " << function->name << " is not the " "same as the type of the function's parameter " "(" << argType->asString() << " value " "for " << paramType->asString() << " parameter.)"); return; } } else { // // input parameter -- it must be possible to cast // the argument type to the parameter type // if (!paramType->canCastFrom (argType)) { MESSAGE_LE (lcontext, ERR_FUNC_ARG_TYPE, arguments[i]->lineNumber, "Cannot convert the type of argument " << i+1 << " " "in call to function " << function->name << " " "to the type of the function's parameter " "(" << argType->asString() << " value " "for " << paramType->asString() << " parameter.)"); return; } } } else { // // We have no function call argument for parameter i. // The parameter must have a default value. // if (!parameters[i].defaultValue) { MESSAGE_LE (lcontext, ERR_FUNC_ARG_NUM, function->lineNumber, "Not enough arguments in call to " "function " << function->name << "."); return; } } } // // If we get here, then the call is valid. // type = functionType->returnType(); }