Example #1
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;
}
Example #2
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;
}