/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * typeinference.cpp
 *
 * Author: pgess <v.melnychenko@xreate.org>
 * Created on April 16, 2017, 10:13 AM
 */

/**
 *  \file typeinference.h
 *  \brief Type inference analysis
 */

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

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

namespace xreate {namespace typeinference {

//TODO type conversion:
//a)    automatically expand types int -> bigger int; int -> floating
//b)    detect exact type of `num` based on max used numeral / function type
//c)    warning if need to truncate (allow/dissalow based on annotations)

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::getDefinition(s), ast);
    }

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



} } //end of namespace xreate::typeinference
