/*
 * typeinference.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on April 16, 2017, 10:13 AM
 */

#include "typeinference.h"
#include "llvmlayer.h"

#include "llvm/IR/Function.h"
#include "llvm/IR/DerivedTypes.h"

namespace xreate {namespace analysis {namespace typeinference {

llvm::Value*
doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){
    if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy())
    {
            llvm::IntegerType* tyTargetInt = llvm::dyn_cast<llvm::IntegerType>(tyTarget);
            llvm::IntegerType* tySourceInt = llvm::dyn_cast<llvm::IntegerType>(source->getType());

            if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){
                    return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget);
            }

            if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){
                    return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget);
            }
    }

    if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){
        return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget);
    }

    return source;
}

ExpandedType
getType(const Expression& expression, const AST& ast){
    if (expression.type.isValid()){
            return ast.expandType(expression.type);
    }

    if (expression.__state == Expression::IDENT){
        Symbol s = Attachments::get<Symbol>(expression);
        return getType(CodeScope::getDeclaration(s), ast);
    }

    assert(false && "Type can't be determined for an expression");
}



} } }