Beispiel #1
0
FunctionCallPtr
Interpreter::newFunctionCall (const std::string &functionName)
{
    Lock lock (_data->mutex);
    
    //
    // Calling a CTL function with variable-size array arguments
    // from C++ is not supported.
    //

    const SymbolInfoPtr info = symtab().lookupSymbol (functionName);

    if (!info)
	THROW (ArgExc, "Cannot find CTL function " << functionName << ".");

    if (!info->isFunction())
	THROW (TypeExc, "CTL object " << functionName << " is not a function "
			"(it is of type " << info->type()->asString() << ").");

    const FunctionTypePtr fType = info->type();
    const ParamVector &parameters = fType->parameters();

    for (int i = parameters.size() - 1; i >= 0; --i)
    {
	const Param &param = parameters[i];
        ArrayTypePtr aType = param.type.cast<ArrayType>();

        if(aType)
        {
            SizeVector sizes;
            aType->sizes (sizes);
	    
            for (int j = 0; j < sizes.size(); j++)
            {
                if (sizes[j] == 0)
                    THROW (ArgExc, "CTL function " << functionName << " "
				   "has a variable-size array "
				   "argument, " << param.name << ", and can "
				   "only be called by another CTL function.");
            }
        }
    }
    
    return newFunctionCallInternal (info, functionName);
}
Beispiel #2
0
TEST(TestFunc, testFunc_ReturnFunc)
{
    PARSE_STATEMENT(L"func chooseStepFunction(backwards: Bool) -> (Int) -> Int {"
                       L"return backwards ? stepBackward : stepForward"
                       L"}");

    FunctionDefPtr func;
    ParametersNodePtr params;
    ParameterNodePtr param;
    TypeIdentifierPtr type;
    FunctionTypePtr rettype;
    TupleTypePtr tupleType;

    ASSERT_NOT_NULL(func = std::dynamic_pointer_cast<FunctionDef>(root));
    ASSERT_EQ(L"chooseStepFunction", func->getName());
    ASSERT_EQ(1, func->numParameters());
    ASSERT_NOT_NULL(params = func->getParameters(0));
    ASSERT_EQ(1, params->numParameters());
    ASSERT_FALSE(params->isVariadicParameters());

    ASSERT_NOT_NULL(param = params->getParameter(0));
    ASSERT_EQ(ParameterNode::None, param->getAccessibility());
    ASSERT_FALSE(param->isShorthandExternalName());
    ASSERT_FALSE(param->isInout());
    ASSERT_NULL(param->getDefaultValue());
    ASSERT_EQ(L"", param->getExternalName());
    ASSERT_EQ(L"backwards", param->getLocalName());
    ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(param->getDeclaredType()));
    ASSERT_EQ(L"Bool", type->getName());

    ASSERT_NOT_NULL(rettype = std::dynamic_pointer_cast<FunctionType>(func->getReturnType()));
    ASSERT_NOT_NULL(tupleType = std::dynamic_pointer_cast<TupleType>(rettype->getArgumentsType()));
    ASSERT_FALSE(tupleType->getVariadicParameters());
    ASSERT_EQ(1, tupleType->numElements());

    ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(tupleType->getElementType(0)));
    ASSERT_EQ(L"Int", type->getName());

    ASSERT_NOT_NULL(type = std::dynamic_pointer_cast<TypeIdentifier>(rettype->getReturnType()));
    ASSERT_EQ(L"Int", type->getName());

}
	TypePtr tryDeduceReturnType(const FunctionTypePtr& funType, const TypeList& argumentTypes) {
		NodeManager& manager = funType->getNodeManager();

		// try deducing variable instantiations the argument types
		auto varInstantiation = types::getTypeVariableInstantiation(manager, funType->getParameterTypes()->getTypes(), argumentTypes);

		// check whether derivation was successful
		if(!varInstantiation) {
			std::stringstream msg;
			msg << "Cannot match arguments (" << join(", ", argumentTypes, print<deref<TypePtr>>()) << ") \n"
				   "         to parameters ("
			    << join(", ", funType->getParameterTypes(), print<deref<TypePtr>>()) << ")";
			throw ReturnTypeDeductionException(msg.str());
		}

		// extract return type
		const TypePtr& resType = funType->getReturnType();

		// compute and return the expected return type
		return varInstantiation->applyTo(manager, resType);
	}
Beispiel #4
0
	TypeVariableSet getTypeVariablesBoundBy(const FunctionTypePtr& funType) {
		// collect all free type variables int he parameters
		TypeVariableSet res;

		// collect all type variables
		for(const auto& paramType : funType->getParameterTypes()) {
			visitDepthFirstOnce(paramType, [&](const TypeVariablePtr& var) {
				res.insert(var);
			});
		}

		// done
		return res;
	}
TypePtr deduceReturnType(const FunctionTypePtr& funType, const TypeList& argumentTypes, bool unitOnFail) {
	try {

		// try deducing the return type ...
		return tryDeduceReturnType(funType, argumentTypes);

	} catch (const ReturnTypeDeductionException&) {

		// didn't work => print a warning
		LOG(DEBUG) << "Unable to deduce return type for call to function of type "
				<< toString(*funType) << " using arguments " << join(", ", argumentTypes, print<deref<TypePtr>>());
	}
	// return null ptr
	return unitOnFail ? funType->getNodeManager().getLangBasic().getUnit() : TypePtr();
}
SimdFunctionCall::SimdFunctionCall
    (SimdInterpreter &interpreter,
     const string &name,
     FunctionTypePtr type,
     SimdInstAddrPtr addr,
     SymbolTable &symbols)
:
     FunctionCall (name),
     _xcontext (interpreter),
     _entryPoint (addr->inst()),
     _symbols(symbols)
{
    {
	SimdReg *returnReg =
	    new SimdReg (type->returnVarying(),
			 type->returnType()->alignedObjectSize());

	_xcontext.stack().push (returnReg, TAKE_OWNERSHIP);

	setReturnValue (new SimdFunctionArg ("",
					     this,
					     type->returnType(),
					     type->returnVarying(),
					     returnReg));
    }

    const ParamVector &parameters = type->parameters();

    vector<FunctionArgPtr> inputs;
    vector<FunctionArgPtr> outputs;
    for (int i = parameters.size() - 1; i >= 0; --i)
    {
	const Param &param = parameters[i];

	SimdReg *paramReg =
	    new SimdReg (param.varying,
		         param.type->alignedObjectSize());

	_xcontext.stack().push (paramReg, TAKE_OWNERSHIP);

	FunctionArgPtr arg = new SimdFunctionArg (param.name,
						  this,
						  param.type,
						  param.varying,
						  paramReg);
	if (param.isWritable())
	    outputs.push_back(arg);
	else
	    inputs.push_back(arg);
    }

    int count = 0;
    for(vector<FunctionArgPtr>::reverse_iterator it = inputs.rbegin();
	it != inputs.rend();
	++it)
    {
	setInputArg (count++, *it);
    }

    count = 0;
    for(vector<FunctionArgPtr>::reverse_iterator it = outputs.rbegin();
	it != outputs.rend();
	++it)
    {
	setOutputArg (count++, *it);
    }
}
Beispiel #7
0
TypeNodePtr Parser::parseType()
{
    Token token;
    TypeNodePtr ret = NULL;
    expect_next(token);
    restore(token);

    if(token == TokenType::OpenParen)
    {
        ret = parseTupleType();
    }
    else if(token.type == TokenType::Identifier && token.identifier.keyword == Keyword::_)
    {
        ret = parseTypeIdentifier();
    }
    else if(token.type == TokenType::Identifier && token.identifier.keyword == Keyword::SelfType)
    {
        ret = parseTypeIdentifier();
    }
    else if(token.getKeyword() == Keyword::Protocol)
    {
        ret = parseProtocolComposition();
    }
    else if(token == TokenType::OpenBracket)
    {
        ret = parseCollectionType();
    }
    else
    {
        unexpected(token);
    }
    do
    {
        if(!next(token))
            break;
        
        //type chaining
        if(token == L"->")
        {
            //function-type → type->type
            TupleTypePtr argType = std::dynamic_pointer_cast<TupleType>(ret);
            if(!argType)
            {
                //wrap ret as a tuple type
                argType = nodeFactory->createTupleType(*ret->getSourceInfo());
                argType->add(false, L"", ret);
            }
            TypeNodePtr retType = parseType();
            FunctionTypePtr func = nodeFactory->createFunctionType(token.state);
            func->setArgumentsType(argType);
            func->setReturnType(retType);
            ret = func;
            continue;
        }
        if(token == TokenType::OpenBracket)
        {
            expect(L"]");
            ArrayTypePtr array = nodeFactory->createArrayType(token.state);
            array->setInnerType(ret);
            ret = array;
            continue;
        }
        if(token == L"?")
        {
            //optional-type → type?
            OptionalTypePtr type = nodeFactory->createOptionalType(token.state);
            type->setInnerType(ret);
            ret = type;
            continue;
        }
        if(token == L"!")
        {
            //implicitly-unwrapped-optional-type → type!
            ImplicitlyUnwrappedOptionalPtr type = nodeFactory->createImplicitlyUnwrappedOptional(token.state);
            type->setInnerType(ret);
            ret = type;
            continue;
        }
        // ‌ metatype-type → type.Type  type.Protocol
        //TODO meta type is not supported
        restore(token);
        break;
    }while(true);
    return ret;
}
Beispiel #8
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();
}
Beispiel #9
0
/**
 * Computes a join or meet type for the given pair of types. The join flag allows to determine
 * whether the join or meet type is computed.
 */
TypePtr getJoinMeetType(const TypePtr& typeA, const TypePtr& typeB, bool join) {
	static const TypePtr fail = 0;

	// add a structure based algorithm for computing the Join-Type

	// shortcut for equal types
	if (*typeA == *typeB) {
		return typeA;
	}

	// the rest depends on the node types
	NodeType nodeTypeA = typeA->getNodeType();
	NodeType nodeTypeB = typeB->getNodeType();

	// handle generic types
	if (nodeTypeA == NT_GenericType && nodeTypeB == NT_GenericType) {
		// let the join computation handle the case
		const GenericTypePtr& genTypeA = static_pointer_cast<const GenericType>(typeA);
		const GenericTypePtr& genTypeB = static_pointer_cast<const GenericType>(typeB);
		return (join) ? getJoinType(genTypeA, genTypeB) : getMeetType(genTypeA, genTypeB);
	}

	// handle vector types (only if array super type of A is a super type of B)

	// make sure typeA is the vector
	if (nodeTypeA != NT_VectorType && nodeTypeB == NT_VectorType) {
		// switch sides
		return getJoinMeetType(typeB, typeA, join);
	}

	// handle vector-array conversion (only works for joins)
	if (join && nodeTypeA == NT_VectorType) {
		VectorTypePtr vector = static_pointer_cast<const VectorType>(typeA);

		// the only potential super type is an array of the same element type
		IRBuilder builder(vector->getNodeManager());
		ArrayTypePtr array = builder.arrayType(vector->getElementType());
		if (isSubTypeOf(typeB, array)) {
			return array;
		}
		// no common super type!
		return fail;
	}

	// the rest can only work if it is of the same kind
	if (nodeTypeA != nodeTypeB) {
		// => no common super type
		return fail;
	}

	// check for functions
	if (nodeTypeA == NT_FunctionType) {
		FunctionTypePtr funTypeA = static_pointer_cast<const FunctionType>(typeA);
		FunctionTypePtr funTypeB = static_pointer_cast<const FunctionType>(typeB);

		// check number of arguments
		auto paramsA = funTypeA->getParameterTypes();
		auto paramsB = funTypeB->getParameterTypes();
		if (paramsA.size() != paramsB.size()) {
			// not matching
			return fail;
		}

		// check function kind
		FunctionKind resKind = funTypeA->getKind();
		if (funTypeA->getKind() != funTypeB->getKind()) {
			// differences are only allowed when going from plain to closure type
			if ((funTypeA->isPlain() && funTypeB->isClosure()) || (funTypeA->isClosure() && funTypeB->isPlain())) {
				resKind = FK_CLOSURE;
			} else {
				return fail;
			}
		}

		// compute join type
		// JOIN/MEET result and argument types - if possible
		TypePtr cur = getJoinMeetType(funTypeA->getReturnType(), funTypeB->getReturnType(), join);
		TypePtr resType = cur;

		// continue with parameters
		TypeList params;
		for (std::size_t i=0; i<paramsA.size(); i++) {
			// ATTENTION: this goes in the reverse direction
			cur = getJoinMeetType(paramsA[i], paramsB[i], !join);

			// if a pair can not be matched => fail
			if (!cur) return fail;

			params.push_back(cur);
		}

		// construct resulting type
		IRBuilder builder(funTypeA->getNodeManager());
		return builder.functionType(params, resType, resKind);
	}

	// everything else does not have a common join/meet type
	return fail;
}
Beispiel #10
0
bool isSubTypeOf(const TypePtr& subType, const TypePtr& superType) {

	// quick check - reflexivity
	if (*subType == *superType) {
		return true;
	}

	// check for recursive types
	if (subType->getNodeType() == NT_RecType || superType->getNodeType() == NT_RecType) {

		// since they are not equivalent we have to compare the unrolled version of the sub with the super type
		if (subType->getNodeType() == NT_RecType) {
			return isSubTypeOf(subType.as<RecTypePtr>()->unroll(), superType);
		}

		if (superType->getNodeType() == NT_RecType) {
			assert(subType->getNodeType() != NT_RecType);
			return isSubTypeOf(subType, superType.as<RecTypePtr>()->unroll());
		}

		assert(false && "How could you get here?");
	}

	// check whether the sub-type is generic
	if (subType->getNodeType() == NT_GenericType || subType->getNodeType() == NT_StructType) {
		// use the delta algorithm for computing all the super-types of the given sub-type
		return isSubTypeOfInternal(subType, superType);
	}

	// check for vector types
	if (subType.isa<VectorTypePtr>() ) {
		VectorTypePtr vector = static_pointer_cast<const VectorType>(subType);
		// potential super type is an array of the same element type
		IRBuilder builder(vector->getNodeManager());
		return *superType == *builder.arrayType(vector->getElementType());
	}

	// for all other relations, the node type has to be the same
	if (subType->getNodeType() != superType->getNodeType()) {
		return false;
	}

	// check function types
	if (subType->getNodeType() == NT_FunctionType) {
		FunctionTypePtr funTypeA = static_pointer_cast<const FunctionType>(subType);
		FunctionTypePtr funTypeB = static_pointer_cast<const FunctionType>(superType);

		// check kind of functions
		if (funTypeA->getKind() != funTypeB->getKind()) {
			// only closure to plain conversion is allowed
			if (!(funTypeB->isClosure() && funTypeA->isPlain())) {
				return false;
			}
		}

		bool res = true;
		res = res && funTypeA->getParameterTypes().size() == funTypeB->getParameterTypes().size();
		res = res && isSubTypeOf(funTypeA->getReturnType(), funTypeB->getReturnType());
		for(std::size_t i = 0; res && i<funTypeB->getParameterTypes().size(); i++) {
			res = res && isSubTypeOf(funTypeB->getParameterTypes()[i], funTypeA->getParameterTypes()[i]);
		}
		return res;
	}

	// check reference types
	if (subType->getNodeType() == NT_RefType) {
		const auto& basic = subType->getNodeManager().getLangBasic();

		// check source / sink
		auto srcRef = subType.as<RefTypePtr>();
		auto trgRef = superType.as<RefTypePtr>();

		// check read/write privileges
		if (trgRef.isRead() && !srcRef.isRead()) return false;
		if (trgRef.isWrite() && !srcRef.isWrite()) return false;

		// check element type
		auto srcElement = subType.as<RefTypePtr>()->getElementType();
		auto trgElement = superType.as<RefTypePtr>()->getElementType();

		// if element types are identical => it is fine
		//if (srcElement == trgElement) return true;
		if(core::analysis::compareTypes(srcElement, trgElement)) return true;

		// if sub-type is ref<any> it is ok
		if (basic.isAny(trgElement)) {
			return true;
		}

		// support nested references
		if (srcElement.isa<RefTypePtr>() && trgElement.isa<RefTypePtr>()) {
			return isSubTypeOf(srcElement, trgElement);
		}

		// a ref<vector<X,Y>> is a sub-type of a ref<array<X,1>>
		if (trgElement.isa<ArrayTypePtr>() && srcElement.isa<VectorTypePtr>()) {
			IRBuilder builder(srcElement.getNodeManager());
			auto one = builder.concreteIntTypeParam(1);

			// array needs to be 1-dimensional and both have to have the same element type
			return trgElement.as<ArrayTypePtr>()->getDimension() == one &&
				   trgElement.as<ArrayTypePtr>()->getElementType() == srcElement.as<VectorTypePtr>()->getElementType();
		}

		// also support references of derived classes being passed to base-type pointer
		if (core::analysis::isObjectType(srcElement) && core::analysis::isObjectType(trgElement)) {
			if (isSubTypeOf(srcElement, trgElement)) {
				return true;
			}
		}

	}

	// no other relations are supported
	return false;
}