* @file
*
* This file implements apis for the calculation of const expression.
*/
#include "TypeCheckerImpl.h"
#include <algorithm>
#include <functional>
#include "Diags.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Node.h"
#include "cangjie/AST/Utils.h"
#include "cangjie/Basic/DiagnosticEngine.h"
#include "cangjie/Utils/FloatFormat.h"
using namespace Cangjie;
using namespace AST;
using namespace Sema;
bool TypeChecker::TypeCheckerImpl::ChkFloatTypeOverflow(const LitConstExpr& lce)
{
auto info = GetFloatTypeInfoByKind(lce.TyKind());
switch (lce.constNumValue.asFloat.flowStatus) {
case Expr::FlowStatus::OVER: {
(void)diag.DiagnoseRefactor(
DiagKindRefactor::sema_float_literal_too_large, lce, lce.GetTy()->String(), info.max);
return false;
}
case Expr::FlowStatus::UNDER: {
(void)diag.DiagnoseRefactor(
DiagKindRefactor::sema_float_literal_too_small, lce, lce.GetTy()->String(), info.min);
return false;
}
default:
break;
}
uint64_t value = 0;
switch (lce.TyKind()) {
case TypeKind::TYPE_FLOAT16: {
float f32 = static_cast<float>(lce.constNumValue.asFloat.value);
value = static_cast<uint64_t>(FloatFormat::Float32ToFloat16(f32) << 1);
break;
}
case TypeKind::TYPE_FLOAT32: {
float f32 = static_cast<float>(lce.constNumValue.asFloat.value);
value = (*reinterpret_cast<uint32_t*>(&f32)) << 1;
break;
}
case TypeKind::TYPE_FLOAT64: {
double f64 = static_cast<double>(lce.constNumValue.asFloat.value);
value = (*reinterpret_cast<uint64_t*>(&f64)) << 1;
break;
}
default: {
return true;
}
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
#endif
if (lce.constNumValue.asFloat.value != 0 && value == 0) {
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
(void)diag.DiagnoseRefactor(
DiagKindRefactor::sema_float_literal_too_small, lce, lce.GetTy()->String(), info.min);
return false;
} else if (value == info.inf) {
(void)diag.DiagnoseRefactor(
DiagKindRefactor::sema_float_literal_too_large, lce, lce.GetTy()->String(), info.max);
return false;
}
return true;
}
bool TypeChecker::TypeCheckerImpl::ChkLitConstExprRange(LitConstExpr& lce)
{
if (!Ty::IsTyCorrect(lce.GetTy())) {
return false;
}
InitializeLitConstValue(lce);
if (lce.GetTy()->IsInteger()) {
lce.constNumValue.asInt.SetOutOfRange(lce.GetTy());
if (lce.constNumValue.asInt.IsOutOfRange()) {
std::string typeName = lce.GetTy()->String();
if (lce.GetTy()->IsIdeal()) {
typeName += "64";
}
(void)diag.DiagnoseRefactor(DiagKindRefactor::sema_exceed_num_value_range,
lce, lce.stringValue, typeName);
lce.SetTy(TypeManager::GetInvalidTy());
return false;
}
} else if (lce.GetTy()->IsFloating()) {
(void)ChkFloatTypeOverflow(lce);
}
return true;
}
bool TypeChecker::TypeCheckerImpl::ReplaceIdealTy(Node& node)
{
if (!Ty::IsTyCorrect(node.GetTy())) {
return false;
}
Ptr<Ty> idealTy = typeManager.ReplaceIdealTy(node.GetTy());
node.SetTy(idealTy);
if (node.astKind == ASTKind::LIT_CONST_EXPR) {
return ChkLitConstExprRange(*StaticAs<ASTKind::LIT_CONST_EXPR>(&node));
}
return true;
}