* @file
*
* This file implements the header file Promotion.h
*/
#include "Promotion.h"
#include "cangjie/AST/Types.h"
#include "cangjie/AST/ASTCasting.h"
#include "cangjie/Utils/Utils.h"
using namespace Cangjie;
using namespace AST;
MultiTypeSubst Promotion::GetPromoteTypeMapping(Ty& from, Ty& target)
{
if (!Ty::IsTyCorrect(&from) || !Ty::IsTyCorrect(&target)) {
return {};
}
auto prRes = Promote(from, target);
if (prRes.empty()) {
return {};
}
MultiTypeSubst mts;
Utils::EraseIf(prRes, [&target](auto& e) { return e->typeArgs.size() != target.typeArgs.size(); });
std::for_each(prRes.begin(), prRes.end(), [&target, &mts](auto prResI) {
for (size_t i = 0; i < target.typeArgs.size(); i++) {
if (auto targetGenParam = DynamicCast<GenericsTy*>(target.typeArgs[i])) {
mts[targetGenParam].emplace(prResI->typeArgs[i]);
}
}
});
return mts;
}
MultiTypeSubst Promotion::GetDowngradeTypeMapping(Ty& target, Ty& upfrom)
{
if (!Ty::IsTyCorrect(&target) || !Ty::IsTyCorrect(&upfrom)) {
return {};
}
auto prRes = Promote(target, upfrom);
if (prRes.empty()) {
return {};
}
MultiTypeSubst mts;
Utils::EraseIf(prRes, [&upfrom](auto& e) { return e->typeArgs.size() != upfrom.typeArgs.size(); });
std::for_each(prRes.begin(), prRes.end(), [&upfrom, &mts](auto prResI) {
for (size_t i = 0; i < prResI->typeArgs.size(); i++) {
if (auto tv = DynamicCast<GenericsTy*>(prResI->typeArgs[i])) {
mts[tv].emplace(upfrom.typeArgs[i]);
}
}
});
return mts;
}
std::set<Ptr<Ty>> Promotion::Promote(Ty& from, Ty& target)
{
if (!Ty::IsTyCorrect(&from) || !Ty::IsTyCorrect(&target)) {
return {};
}
bool useTarget = from.IsNothing() || target.IsAny() || (target.IsCType() && Ty::IsMetCType(from));
if (useTarget) {
return {&target};
}
if (from.IsPrimitive() && target.IsPrimitive()) {
return PromoteHandleIdealTys(from, target);
}
if (from.IsFunc() && target.IsFunc()) {
return PromoteHandleFunc(from, target);
}
if (from.IsTuple() && target.IsTuple()) {
return PromoteHandleTuple(from, target);
}
if (auto res = PromoteHandleTyVar(from, target); !res.empty()) {
return res;
}
return PromoteHandleNominal(from, target);
}
std::set<Ptr<AST::Ty>> Promotion::Downgrade(AST::Ty& target, AST::Ty& upfrom)
{
auto dMaps = GetDowngradeTypeMapping(target, upfrom);
if (dMaps.size() < target.typeArgs.size()) {
return {};
} else {
return tyMgr.GetInstantiatedTys(&target, dMaps);
}
}
std::set<Ptr<Ty>> Promotion::PromoteHandleTyVar(Ty& from, Ty& target)
{
if (!from.IsGeneric()) {
return {};
}
auto genericTy = RawStaticCast<GenericsTy*>(&from);
for (auto& ty : genericTy->upperBounds) {
if (auto res = Promote(*ty, target); !res.empty()) {
return res;
}
}
return {};
}
std::set<Ptr<Ty>> Promotion::PromoteHandleIdealTys(Ty& from, Ty& target) const
{
if (from.kind == target.kind) {
return {&from};
}
if (from.kind == TypeKind::TYPE_IDEAL_INT && target.IsInteger()) {
return {&target};
} else if (from.kind == TypeKind::TYPE_IDEAL_FLOAT && target.IsFloating()) {
return {&target};
} else {
return {};
}
}
std::set<Ptr<Ty>> Promotion::PromoteHandleFunc(Ty& from, Ty& target)
{
if (tyMgr.IsTyEqual(&from, &target)) {
return {&from};
} else {
return {};
}
}
std::set<Ptr<Ty>> Promotion::PromoteHandleTuple(Ty& from, Ty& target)
{
if (tyMgr.IsTyEqual(&from, &target)) {
return {&from};
} else {
return {};
}
}
std::set<Ptr<Ty>> Promotion::PromoteHandleNominal(Ty& from, const Ty& target)
{
if (Ty::GetDeclPtrOfTy<InheritableDecl>(&from) == Ty::GetDeclPtrOfTy<InheritableDecl>(&target)) {
return {&from};
}
TypeSubst typeMapping;
auto emplaceElem = [&from, &typeMapping](const std::vector<Ptr<Ty>>& tyVars) {
if (tyVars.size() != from.typeArgs.size()) {
return;
}
for (size_t i = 0; i < tyVars.size(); i++) {
typeMapping.emplace(StaticCast<GenericsTy*>(tyVars[i]), from.typeArgs[i]);
}
};
if (from.IsClass()) {
auto classTy = RawStaticCast<ClassTy*>(&from);
CJC_ASSERT(classTy->decl);
if (classTy->decl->GetTy()) {
emplaceElem(classTy->declPtr->GetTy()->typeArgs);
}
} else if (from.IsInterface()) {
auto interfaceTy = RawStaticCast<InterfaceTy*>(&from);
CJC_ASSERT(interfaceTy->decl);
if (interfaceTy->decl->GetTy()) {
emplaceElem(interfaceTy->declPtr->GetTy()->typeArgs);
}
} else if (from.IsStruct()) {
auto structTy = RawStaticCast<StructTy*>(&from);
CJC_ASSERT(structTy->decl);
if (structTy->decl->GetTy()) {
emplaceElem(structTy->declPtr->GetTy()->typeArgs);
}
} else if (from.IsEnum()) {
auto enumTy = RawStaticCast<EnumTy*>(&from);
CJC_ASSERT(enumTy->decl);
if (enumTy->decl->GetTy()) {
emplaceElem(enumTy->declPtr->GetTy()->typeArgs);
}
}
std::set<Ptr<Ty>> res;
auto supTys = tyMgr.GetAllSuperTys(from, typeMapping);
for (auto ty : supTys) {
auto cly = DynamicCast<ClassLikeTy*>(ty);
if (cly && Ty::GetDeclPtrOfTy(cly) == Ty::GetDeclPtrOfTy(&target)) {
res.insert(cly);
}
}
return res;
}