* @file
*
* This file implements inheritance checking of structure declarations.
*/
#include "StructInheritanceChecker.h"
#include "cangjie/AST/Clone.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Node.h"
#include "cangjie/AST/Types.h"
#include "cangjie/AST/Utils.h"
#include "cangjie/Sema/TypeManager.h"
#include "BuiltInOperatorUtil.h"
#include "TypeCheckUtil.h"
using namespace Cangjie;
using namespace AST;
using namespace TypeCheckUtil;
bool StructInheritanceChecker::IsBuiltInOperatorFuncInExtend(
const MemberSignature& member, const Decl& structDecl) const
{
if (structDecl.astKind != ASTKind::EXTEND_DECL || !member.decl->IsFunc() ||
!Ty::IsTyCorrect(member.decl->GetTy()) || !member.decl->TestAttr(Attribute::ABSTRACT, Attribute::OPERATOR)) {
return false;
}
auto ed = RawStaticCast<const ExtendDecl*>(&structDecl);
auto fd = RawStaticCast<const FuncDecl*>(member.decl);
auto funcTy = RawStaticCast<FuncTy*>(member.ty);
auto iFuncRetTy = funcTy->retTy;
const std::vector<Ptr<Ty>>& paramTys = funcTy->paramTys;
Ptr<Ty> thisTy = ed->extendedType->GetTy();
if (paramTys.size() == 1 && thisTy && paramTys[0] && IsBuiltinBinaryExpr(fd->op, *thisTy, *paramTys[0])) {
TypeKind returnTyKind = GetBuiltinBinaryExprReturnKind(fd->op, thisTy->kind);
auto expectedRetTy = TypeManager::GetPrimitiveTy(returnTyKind);
if (expectedRetTy == iFuncRetTy) {
CreateBuiltInBinaryOperatorFunc(fd->op, paramTys[0], *const_cast<ExtendDecl*>(ed), returnTyKind);
} else {
diag.DiagnoseRefactor(DiagKindRefactor::sema_return_type_incompatible, structDecl, fd->identifier);
}
return true;
} else if (paramTys.empty() && thisTy && IsBuiltinUnaryExpr(fd->op, *thisTy)) {
TypeKind returnTyKind = GetBuiltinUnaryOpReturnKind(fd->op, ed->TyKind());
auto expectedRetTy = TypeManager::GetPrimitiveTy(returnTyKind);
if (expectedRetTy == iFuncRetTy) {
CreateBuiltInUnaryOperatorFunc(fd->op, *const_cast<ExtendDecl*>(ed));
} else {
diag.DiagnoseRefactor(DiagKindRefactor::sema_return_type_incompatible, structDecl, fd->identifier);
}
return true;
}
return false;
}
void StructInheritanceChecker::CreateBuiltInUnaryOperatorFunc(TokenKind op, ExtendDecl& ed) const
{
TypeKind returnTyKind = GetBuiltinUnaryOpReturnKind(op, ed.TyKind());
auto returnTy = TypeManager::GetPrimitiveTy(returnTyKind);
auto nothingTy = TypeManager::GetNothingTy();
auto fd = MakeOwnedNode<FuncDecl>();
fd->toBeCompiled = true;
fd->EnableAttr(Attribute::IN_EXTEND, Attribute::PUBLIC, Attribute::OPERATOR, Attribute::IMPLICIT_ADD);
CopyBasicInfo(&ed, fd.get());
fd->moduleName = ed.moduleName;
fd->fullPackageName = ed.fullPackageName;
fd->op = op;
fd->identifier = SrcIdentifier{TOKENS[static_cast<int>(op)]};
fd->SetTy(typeManager.GetFunctionTy({}, returnTy));
fd->outerDecl = &ed;
auto funcBody = MakeOwnedNode<FuncBody>();
funcBody->paramLists.emplace_back(MakeOwnedNode<FuncParamList>());
funcBody->funcDecl = fd.get();
funcBody->SetTy(fd->GetTy());
auto retType = MakeOwnedNode<PrimitiveType>();
retType->kind = returnTyKind;
retType->SetTy(returnTy);
funcBody->retType = std::move(retType);
auto block = MakeOwnedNode<Block>();
block->SetTy(nothingTy);
auto thisExpr = MakeOwnedNode<RefExpr>();
thisExpr->isThis = true;
thisExpr->ref.identifier = "this";
thisExpr->SetTy(ed.GetTy());
auto ue = MakeOwnedNode<UnaryExpr>();
ue->op = op;
ue->expr = std::move(thisExpr);
ue->SetTy(returnTy);
auto returnExpr = MakeOwnedNode<ReturnExpr>();
returnExpr->expr = std::move(ue);
returnExpr->SetTy(nothingTy);
returnExpr->refFuncBody = funcBody.get();
block->body.emplace_back(std::move(returnExpr));
funcBody->body = std::move(block);
fd->funcBody = std::move(funcBody);
AddCurFile(*fd, ed.curFile);
ed.members.push_back(std::move(fd));
}
void StructInheritanceChecker::CreateBuiltInBinaryOperatorFunc(
TokenKind op, Ptr<Ty> rightTy, ExtendDecl& ed, TypeKind returnTyKind) const
{
auto retTy = TypeManager::GetPrimitiveTy(returnTyKind);
auto nothingTy = TypeManager::GetNothingTy();
auto fd = MakeOwnedNode<FuncDecl>();
fd->toBeCompiled = true;
fd->EnableAttr(Attribute::IN_EXTEND, Attribute::PUBLIC, Attribute::OPERATOR, Attribute::IMPLICIT_ADD);
CopyBasicInfo(&ed, fd.get());
fd->moduleName = ed.moduleName;
fd->fullPackageName = ed.fullPackageName;
fd->op = op;
fd->identifier = SrcIdentifier{TOKENS[static_cast<int>(op)]};
fd->SetTy(typeManager.GetFunctionTy({rightTy}, retTy));
fd->outerDecl = &ed;
auto funcBody = MakeOwnedNode<FuncBody>();
funcBody->SetTy(fd->GetTy());
funcBody->funcDecl = fd.get();
auto retType = MakeOwnedNode<PrimitiveType>();
retType->kind = returnTyKind;
retType->SetTy(retTy);
funcBody->retType = std::move(retType);
auto rightParam = MakeOwnedNode<FuncParam>();
rightParam->SetTy(rightTy);
rightParam->identifier = "right";
auto block = MakeOwnedNode<Block>();
block->SetTy(nothingTy);
auto leftExpr = MakeOwnedNode<RefExpr>();
leftExpr->isThis = true;
leftExpr->ref.identifier = "this";
leftExpr->SetTy(ed.GetTy());
auto rightExpr = MakeOwnedNode<RefExpr>();
rightExpr->ref.identifier = "right";
rightExpr->ref.target = rightParam.get();
rightExpr->SetTy(rightTy);
auto be = MakeOwnedNode<BinaryExpr>();
be->op = op;
be->leftExpr = std::move(leftExpr);
be->rightExpr = std::move(rightExpr);
be->SetTy(retTy);
auto returnExpr = MakeOwnedNode<ReturnExpr>();
returnExpr->expr = std::move(be);
returnExpr->SetTy(nothingTy);
returnExpr->refFuncBody = funcBody.get();
auto paramList = MakeOwnedNode<FuncParamList>();
paramList->params.emplace_back(std::move(rightParam));
funcBody->paramLists.emplace_back(std::move(paramList));
block->body.emplace_back(std::move(returnExpr));
funcBody->body = std::move(block);
fd->funcBody = std::move(funcBody);
AddCurFile(*fd, ed.curFile);
ed.members.push_back(std::move(fd));
}