* @file
*
* This file implements confliction checking of generic upper bounds.
*/
#include "StructInheritanceChecker.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Node.h"
#include "cangjie/AST/Types.h"
#include "cangjie/AST/Utils.h"
#include "cangjie/AST/Walker.h"
#include "cangjie/Sema/TypeManager.h"
#include "TypeCheckUtil.h"
using namespace Cangjie;
using namespace AST;
using namespace TypeCheckUtil;
namespace {
Ptr<Ty> GetSmallestClassTy(TypeManager& tyMgr, const std::set<Ptr<Ty>>& uppers)
{
Ptr<Ty> smallest = nullptr;
for (auto it : uppers) {
if (!it->IsClass()) {
continue;
}
if (!Ty::IsTyCorrect(smallest) || tyMgr.IsSubtype(it, smallest)) {
smallest = it;
}
}
return smallest;
}
}
void StructInheritanceChecker::CheckAllUpperBoundsConfliction()
{
std::vector<Ptr<const Generic>> genericsWithConstraint;
Walker(&pkg, [&genericsWithConstraint](auto node) {
if (node->TestAttr(Attribute::GENERIC_INSTANTIATED)) {
return VisitAction::SKIP_CHILDREN;
}
if (auto generic = DynamicCast<Generic*>(node); generic && !generic->genericConstraints.empty()) {
(void)genericsWithConstraint.emplace_back(generic);
return VisitAction::SKIP_CHILDREN;
}
return VisitAction::WALK_CHILDREN;
}).Walk();
for (auto generic : std::as_const(genericsWithConstraint)) {
CheckUpperBoundsConfliction(*generic);
}
}
void StructInheritanceChecker::CheckUpperBoundsConfliction(const Generic& generic)
{
for (auto& gc : generic.genericConstraints) {
CJC_ASSERT(gc && gc->type);
auto gTy = DynamicCast<GenericsTy*>(gc->type->GetTy());
if (gTy == nullptr || gTy->decl->TestAttr(Attribute::IN_REFERENCE_CYCLE)) {
continue;
}
auto uppers = gTy->upperBounds;
if (uppers.empty()) {
continue;
}
auto classTy = GetSmallestClassTy(typeManager, uppers);
Utils::EraseIf(uppers, [](auto ty) { return !ty->IsInterface(); });
MemberMap inheritedMembers;
for (auto iTy : uppers) {
auto interfaceDecl = Ty::GetDeclPtrOfTy<InheritableDecl>(iTy);
if (auto found = structInheritedMembers.find(interfaceDecl); found != structInheritedMembers.end()) {
MergeInheritedMembers(inheritedMembers, found->second, *iTy, true);
}
}
if (auto cd = Ty::GetDeclPtrOfTy<InheritableDecl>(classTy)) {
auto members = GetInheritedSuperMembers(*cd, *classTy, *generic.curFile);
MergeInheritedMembers(inheritedMembers, members, *classTy, true);
}
for (auto& [_, member] : std::as_const(inheritedMembers)) {
if (member.inconsistentTypes.empty()) {
continue;
}
DiagnoseInheritedInsconsistType(member, *gc);
}
}
}