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();
}
	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);
	}
Example #3
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;
}