Files
UnrealEngine/Engine/Source/Runtime/VerseCompiler/Public/uLang/Semantics/SemanticClass.h
2025-05-18 13:04:45 +08:00

383 lines
13 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// uLang Compiler Public API
#pragma once
#include "uLang/Common/Containers/SharedPointerSet.h"
#include "uLang/Common/Containers/UniquePointerSet.h"
#include "uLang/Semantics/Attributable.h"
#include "uLang/Semantics/Definition.h"
#include "uLang/Semantics/DataDefinition.h"
#include "uLang/Semantics/MemberOrigin.h"
#include "uLang/Semantics/SemanticFunction.h"
#include "uLang/Semantics/SemanticInterface.h"
#include "uLang/Semantics/SemanticScope.h"
#include "uLang/Semantics/SmallDefinitionArray.h"
#include "uLang/Semantics/StructOrClass.h"
#include "uLang/Semantics/TypeVariable.h"
#include "uLang/Semantics/VisitStamp.h"
#define UE_API VERSECOMPILER_API
namespace uLang
{
// Forward declarations
class CClassDefinition;
/**
* Class defining a class instance / object
* [Might break off CStructType to differentiate stack based types.]
**/
class CClass : public CNominalType, public CLogicalScope
{
public:
static const ETypeKind StaticTypeKind = ETypeKind::Class;
static const CDefinition::EKind StaticDefinitionKind = CDefinition::EKind::Class;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public data
CClassDefinition* const _Definition;
const EStructOrClass _StructOrClass;
CClass* _Superclass;
TArray<CInterface*> _SuperInterfaces;
// Flattened array of all interfaces this class inherits (including interfaces from its super-class).
// Not initially filled out -- cached after we've fully constructed the whole type hierarchy.
TArray<CInterface*> _AllInheritedInterfaces;
SEffectSet _ConstructorEffects;
// Kept alive via _Definition's IrNode's (CExprClassDefinition) Members field.
// We don't hold a shared reference to this because the Ir tree has to be
// destroyed before the AST.
TArray<CExprCodeBlock*> _IrBlockClauses;
CClass* _GeneralizedClass{this};
TArray<STypeVariableSubstitution> _TypeVariableSubstitutions;
TURefArray<CClass> _InstantiatedClasses;
TUPtr<CClass> _OwnedNegativeClass;
CClass* _NegativeClass;
bool _bHasCyclesBroken{false};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Methods
// Construct a generalized positive class
UE_API CClass(
CClassDefinition*,
CScope& EnclosingScope,
CClass* Superclass = nullptr,
TArray<CInterface*>&& SuperInterfaces = {},
EStructOrClass = EStructOrClass::Class,
SEffectSet ConstructorEffects = EffectSets::ClassAndInterfaceDefault);
// Construct a positive class instantiation
UE_API CClass(
CScope* ParentScope,
CClassDefinition*,
EStructOrClass,
CClass* Superclass,
TArray<CInterface*>&& SuperInterfaces,
SEffectSet ConstructorEffects,
CClass* GeneralizedClass,
TArray<STypeVariableSubstitution>);
// Construct a negative class from a positive class
UE_API explicit CClass(CClass* PositiveClass);
using CTypeBase::GetProgram;
UE_API const CTypeType* GetTypeType() const;
UE_API void SetSuperclass(CClass* SuperClass);
/// Determine if current class is the same class or a subclass of the specified `Class`
bool IsClass(const CClass& Class) const;
/// Determine if current class is a subclass / descendant / child of the specified `Class` (and not the same class!)
bool IsSubclassOf(const CClass& Superclass) const;
/// Determine if current class is a superclass / ancestor / parent of the specified `Class` (and not the same class!)
bool IsSuperclassOf(const CClass& Subclass) const;
/// Determine if current class implements `Interface`
UE_API bool ImplementsInterface(const CInterface& Interface) const;
/// Is this class a struct?
bool IsStruct() const { return _StructOrClass == EStructOrClass::Struct; }
bool IsNative() const { return Definition()->IsNative(); }
UE_API bool IsAbstract() const;
UE_API bool IsPersistent() const;
UE_API bool IsUnique() const;
/// Does this class hold a concrete attribute?
UE_API bool HasConcreteAttribute() const;
/// Return first class in the inheritance chain that contains the concrete attribute or null
UE_API const CClass* FindConcreteBase() const;
/// Return topmost class in the inheritance chain that contains the concrete attribute or null
UE_API const CClass* FindInitialConcreteBase() const;
/// Is this class concrete either by having a concrete attribute or inheriting one
bool IsConcrete() const { return FindConcreteBase() != nullptr; }
/// Does this class hold a castable attribute?
UE_API bool HasCastableAttribute() const;
/// Return first class in the inheritance chain that contains the castable attribute. Otherwise null
UE_API const CNominalType* FindExplicitlyCastableBase() const;
/// Is this class castable either by having a castable attribute or inheriting one
bool IsExplicitlyCastable() const override { return FindExplicitlyCastableBase() != nullptr; }
/// Does this class hold a <final_super_base> attribute?
UE_API bool HasFinalSuperBaseAttribute() const;
/// Does this class hold a <final_super> attribute?
UE_API bool HasFinalSuperAttribute() const;
// CScope interface
virtual CSymbol GetScopeName() const override { return Definition()->GetName(); }
virtual const CTypeBase* ScopeAsType() const override { return this; }
virtual const CDefinition* ScopeAsDefinition() const override { return Definition(); }
UE_API virtual SAccessLevel GetDefaultDefinitionAccessLevel() const override;
UE_API virtual void CreateNegativeDataDefinition(const CDataDefinition& PositiveDataDefinition) const override;
UE_API virtual void CreateNegativeFunction(const CFunction& PositiveFunction) const override;
// CLogicalScope interface.
UE_API virtual SmallDefinitionArray FindDefinitions(
const CSymbol& Name,
EMemberOrigin Origin = EMemberOrigin::InheritedOrOriginal,
const SQualifier& Qualifier = SQualifier::Unknown(),
const CAstPackage* ContextPackage = nullptr,
VisitStampType VisitStamp = GenerateNewVisitStamp()) const override;
// CTypeBase interface.
UE_API virtual CUTF8String AsCodeRecursive(ETypeSyntaxPrecedence OuterPrecedence, TArray<const CFlowType*>& VisitedFlowTypes, bool bLinkable, ETypeStringFlag Flag) const override;
UE_API virtual SmallDefinitionArray FindInstanceMember(const CSymbol& Name, EMemberOrigin Origin, const SQualifier& Qualifier = SQualifier::Unknown(), const CAstPackage* ContextPackage = nullptr, VisitStampType VisitStamp = CScope::GenerateNewVisitStamp()) const override;
UE_API virtual EComparability GetComparability() const override;
UE_API EComparability GetComparability(VisitStampType) const;
UE_API bool IsPersistable() const override;
virtual void SetRevision(SemanticRevision Revision) override;
virtual bool CanBeCustomAccessorDataType() const override { return true; }
virtual bool CanBePredictsVarDataType() const override { return !IsStruct(); }
// CNominalType interface.
virtual const CDefinition* Definition() const override;
template<typename TFunc>
void ForEachAncestorClassOrInterface(const TFunc& Func)
{
for (CInterface* Interface : _AllInheritedInterfaces)
{
Func(Interface, nullptr, Interface);
}
for (CClass* Class = _Superclass; Class; Class = Class->_Superclass)
{
Func(Class, Class, nullptr);
}
}
bool HasAttributeClass(const CClass* AttributeClass, const CSemanticProgram& Program) const;
UE_API void AddAttribute(SAttribute) const;
TOptional<SAttribute> FindAttribute(const CClass* AttributeClass, const CSemanticProgram& Program) const;
bool HasCyclesBroken() const;
bool IsParametric() const
{
return !!(_OwnedNegativeClass ? _TypeVariableSubstitutions : _NegativeClass->_TypeVariableSubstitutions).Num();
}
}; // CClass
class CClassDefinition : public CDefinition, public CClass
{
public:
CAttributable _EffectAttributable;
TOptional<SAccessLevel> _ConstructorAccessLevel;
CClassDefinition(const CSymbol& ClassName,
CScope& EnclosingScope,
CClass* Superclass = nullptr,
TArray<CInterface*>&& SuperInterfaces = {},
EStructOrClass StructOrClass = EStructOrClass::Class)
: CDefinition(StaticDefinitionKind, EnclosingScope, ClassName)
, CClass(this, EnclosingScope, Superclass, Move(SuperInterfaces), StructOrClass)
{}
using CAttributable::HasAttributeClass;
using CAttributable::AddAttribute;
using CAttributable::FindAttribute;
SAccessLevel DerivedConstructorAccessLevel() const
{
return _ConstructorAccessLevel.Get(SAccessLevel::EKind::Public);
}
// CDefinition interface.
UE_API void SetAstNode(CExprClassDefinition* AstNode);
UE_API CExprClassDefinition* GetAstNode() const;
UE_API void SetIrNode(CExprClassDefinition* AstNode);
UE_API CExprClassDefinition* GetIrNode(bool bForce = false) const;
virtual const CLogicalScope* DefinitionAsLogicalScopeNullable() const override { return this; }
virtual bool IsPersistenceCompatConstraint() const override { return IsPersistable(); }
UE_API TArray<TSRef<CExpressionBase>> FindMembersWithPredictsAttribute() const;
};
class CInstantiatedClass : public CInstantiatedType
{
public:
CInstantiatedClass(CSemanticProgram& Program, const CClass& Class, ETypePolarity Polarity, TArray<STypeVariableSubstitution> Arguments)
: CInstantiatedType(Program, Polarity, Move(Arguments))
, _Class(&Class)
{
}
virtual bool CanBeCustomAccessorDataType() const override { return false; };
protected:
UE_API virtual const CNormalType& CreateNormalType() const override;
private:
const CClass* _Class;
};
// Eagerly instantiate a class.
VERSECOMPILER_API CClass* InstantiateClass(const CClass&, ETypePolarity, const TArray<STypeVariableSubstitution>&);
VERSECOMPILER_API void SetNegativeClassMemberDefinitionTypes(const CClass& PositiveClass);
//=======================================================================================
// CClass Inline Methods
//=======================================================================================
//---------------------------------------------------------------------------------------
inline const CDefinition* CClass::Definition() const
{
return _Definition;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE void CClass::SetSuperclass(CClass* Superclass)
{
// TODO-Verse: add _Subclasses
_Superclass = Superclass;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CClass::IsClass(const CClass& Class) const
{
TArrayG<const CClass*, TInlineElementAllocator<16>> SeenClasses;
const CClass* RelatedClass = this;
do
{
if (SeenClasses.Contains(RelatedClass))
{
return false;
}
SeenClasses.Push(RelatedClass);
if (RelatedClass == &Class)
{
return true;
}
RelatedClass = RelatedClass->_Superclass;
} while (RelatedClass);
return false;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CClass::IsSubclassOf(const CClass& Superclass) const
{
ULANG_ASSERT(HasCyclesBroken());
const CClass* RelatedClass = _Superclass;
while (RelatedClass)
{
if (RelatedClass == &Superclass)
{
return true;
}
RelatedClass = RelatedClass->_Superclass;
}
return false;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CClass::IsSuperclassOf(const CClass& Subclass) const
{
const CClass* RelatedClass = Subclass._Superclass;
while (RelatedClass)
{
if (RelatedClass == this)
{
return true;
}
RelatedClass = RelatedClass->_Superclass;
}
return false;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE void CClass::SetRevision(SemanticRevision Revision)
{
CClass* Class = this;
do
{
ULANG_ENSUREF(Revision >= Class->GetRevision(), "Revision to be set must not be smaller than existing revisions.");
if (Class->GetRevision() == Revision)
{
break;
}
Class->CLogicalScope::SetRevision(Revision);
Class = Class->_Superclass;
} while (Class);
}
inline bool CClass::HasAttributeClass(const CClass* AttributeClass, const CSemanticProgram& Program) const
{
return _Definition->HasAttributeClass(AttributeClass, Program);
}
inline void CClass::AddAttribute(SAttribute Attribute) const
{
return _Definition->AddAttribute(Move(Attribute));
}
inline TOptional<SAttribute> CClass::FindAttribute(const CClass* AttributeClass, const CSemanticProgram& Program) const
{
return _Definition->FindAttribute(AttributeClass, Program);
}
inline bool CClass::HasCyclesBroken() const
{
return _Definition->_bHasCyclesBroken;
}
} // namespace uLang
#undef UE_API