// 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 _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 _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 _IrBlockClauses; CClass* _GeneralizedClass{this}; TArray _TypeVariableSubstitutions; TURefArray _InstantiatedClasses; TUPtr _OwnedNegativeClass; CClass* _NegativeClass; bool _bHasCyclesBroken{false}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Methods // Construct a generalized positive class UE_API CClass( CClassDefinition*, CScope& EnclosingScope, CClass* Superclass = nullptr, TArray&& SuperInterfaces = {}, EStructOrClass = EStructOrClass::Class, SEffectSet ConstructorEffects = EffectSets::ClassAndInterfaceDefault); // Construct a positive class instantiation UE_API CClass( CScope* ParentScope, CClassDefinition*, EStructOrClass, CClass* Superclass, TArray&& SuperInterfaces, SEffectSet ConstructorEffects, CClass* GeneralizedClass, TArray); // 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 attribute? UE_API bool HasFinalSuperBaseAttribute() const; /// Does this class hold a 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& 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 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 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 _ConstructorAccessLevel; CClassDefinition(const CSymbol& ClassName, CScope& EnclosingScope, CClass* Superclass = nullptr, TArray&& 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> FindMembersWithPredictsAttribute() const; }; class CInstantiatedClass : public CInstantiatedType { public: CInstantiatedClass(CSemanticProgram& Program, const CClass& Class, ETypePolarity Polarity, TArray 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&); 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> 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 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