Example #1
0
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 &parameters = 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();
}