mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
The first bug is that we weren't computing isolation correctly for nested defers. This is an unlikely pattern of code, but it's good to fix. The second bug is that getActorIsolationOfContext was looking through defers, but getActorIsolation itself was not. This was causing defer bodies to be emitted in SILGen without an isolation parameter, which meant that #isolation could not possibly provide the right value. Fixing this involves teaching SILGen that non-async functions can have nonisolated(nonsending) isolation, but that's relatively straightforward. This commit doesn't fix #isolation or adequately test SILGen, but that'll be handled in a follow-up.
10160 lines
361 KiB
C++
10160 lines
361 KiB
C++
//===--- Decl.h - Swift Language Declaration ASTs ---------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the Decl class and subclasses.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_DECL_H
|
|
#define SWIFT_DECL_H
|
|
|
|
#include "swift/AST/AccessScope.h"
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/AvailabilityRange.h"
|
|
#include "swift/AST/CaptureInfo.h"
|
|
#include "swift/AST/ClangNode.h"
|
|
#include "swift/AST/ConcreteDeclRef.h"
|
|
#include "swift/AST/DefaultArgumentKind.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/ForeignAsyncConvention.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/AST/FreestandingMacroExpansion.h"
|
|
#include "swift/AST/GenericParamKey.h"
|
|
#include "swift/AST/IfConfigClause.h"
|
|
#include "swift/AST/Import.h"
|
|
#include "swift/AST/Initializer.h"
|
|
#include "swift/AST/LayoutConstraint.h"
|
|
#include "swift/AST/LifetimeAnnotation.h"
|
|
#include "swift/AST/ProtocolConformanceOptions.h"
|
|
#include "swift/AST/ReferenceCounting.h"
|
|
#include "swift/AST/RequirementSignature.h"
|
|
#include "swift/AST/StorageImpl.h"
|
|
#include "swift/AST/TypeAlignments.h"
|
|
#include "swift/AST/TypeResolutionStage.h"
|
|
#include "swift/AST/TypeWalker.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/Basic/ArrayRefView.h"
|
|
#include "swift/Basic/Compiler.h"
|
|
#include "swift/Basic/Debug.h"
|
|
#include "swift/Basic/InlineBitfield.h"
|
|
#include "swift/Basic/Located.h"
|
|
#include "swift/Basic/Nullability.h"
|
|
#include "swift/Basic/NullablePtr.h"
|
|
#include "swift/Basic/OptionalEnum.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Basic/SwiftObjectHeader.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/TinyPtrVector.h"
|
|
#include "llvm/Support/TrailingObjects.h"
|
|
#include <map>
|
|
#include <type_traits>
|
|
|
|
namespace clang {
|
|
class PointerAuthQualifier;
|
|
} // end namespace clang
|
|
|
|
namespace swift {
|
|
enum class AccessSemantics : unsigned char;
|
|
class AccessorDecl;
|
|
class ApplyExpr;
|
|
class AvailabilityRange;
|
|
class AvailabilityDomain;
|
|
class GenericEnvironment;
|
|
class ArchetypeType;
|
|
class ASTContext;
|
|
struct ASTNode;
|
|
class ASTPrinter;
|
|
class ASTWalker;
|
|
enum class BuiltinMacroKind: uint8_t;
|
|
class ConstructorDecl;
|
|
class DestructorDecl;
|
|
class DiagnosticEngine;
|
|
class DynamicSelfType;
|
|
class Type;
|
|
class Expr;
|
|
struct ExternalSourceLocs;
|
|
class CaptureListExpr;
|
|
class DeclRefExpr;
|
|
class LiteralExpr;
|
|
class BraceStmt;
|
|
class DeclAttributes;
|
|
class GenericContext;
|
|
class GenericParamList;
|
|
class GenericSignature;
|
|
class GenericTypeParamDecl;
|
|
class GenericTypeParamType;
|
|
class MacroDecl;
|
|
class MacroDefinition;
|
|
class ModuleDecl;
|
|
class NamedPattern;
|
|
enum NLOptions : unsigned;
|
|
class EnumCaseDecl;
|
|
class EnumElementDecl;
|
|
class ParameterList;
|
|
class ParameterTypeFlags;
|
|
class Pattern;
|
|
struct PrintOptions;
|
|
struct PropertyWrapperAuxiliaryVariables;
|
|
class PropertyWrapperInitializerInfo;
|
|
struct PropertyWrapperTypeInfo;
|
|
struct PropertyWrapperMutability;
|
|
class ProtocolDecl;
|
|
class PolymorphicEffectRequirementList;
|
|
class ProtocolType;
|
|
struct RawComment;
|
|
enum class ResilienceExpansion : unsigned;
|
|
class ReturnStmt;
|
|
enum class EffectKind : uint8_t;
|
|
enum class PolymorphicEffectKind : uint8_t;
|
|
class TrailingWhereClause;
|
|
class TypeAliasDecl;
|
|
class Stmt;
|
|
class SubscriptDecl;
|
|
class UnboundGenericType;
|
|
class ValueDecl;
|
|
class VarDecl;
|
|
class OpaqueReturnTypeRepr;
|
|
class Witness;
|
|
|
|
namespace ast_scope {
|
|
class AbstractPatternEntryScope;
|
|
class GenericParamScope;
|
|
class PatternEntryDeclScope;
|
|
class PatternEntryInitializerScope;
|
|
} // namespace ast_scope
|
|
|
|
enum class DeclKind : uint8_t {
|
|
#define DECL(Id, Parent) Id,
|
|
#define LAST_DECL(Id) Last_Decl = Id,
|
|
#define DECL_RANGE(Id, FirstId, LastId) \
|
|
First_##Id##Decl = FirstId, Last_##Id##Decl = LastId,
|
|
#include "swift/AST/DeclNodes.def"
|
|
};
|
|
enum : unsigned { NumDeclKindBits =
|
|
countBitsUsed(static_cast<unsigned>(DeclKind::Last_Decl)) };
|
|
|
|
|
|
/// Fine-grained declaration kind that provides a description of the
|
|
/// kind of entity a declaration represents, as it would be used in
|
|
/// diagnostics.
|
|
///
|
|
/// For example, \c FuncDecl is a single declaration class, but it has
|
|
/// several descriptive entries depending on whether it is an
|
|
/// operator, global function, local function, method, (observing)
|
|
/// accessor, etc.
|
|
enum class DescriptiveDeclKind : uint8_t {
|
|
Import,
|
|
Extension,
|
|
EnumCase,
|
|
TopLevelCode,
|
|
PatternBinding,
|
|
Var,
|
|
Param,
|
|
Let,
|
|
Property,
|
|
StaticProperty,
|
|
ClassProperty,
|
|
DistributedProperty,
|
|
InfixOperator,
|
|
PrefixOperator,
|
|
PostfixOperator,
|
|
PrecedenceGroup,
|
|
TypeAlias,
|
|
GenericTypeParam,
|
|
AssociatedType,
|
|
Type,
|
|
Enum,
|
|
Struct,
|
|
Class,
|
|
Actor,
|
|
DistributedActor,
|
|
Protocol,
|
|
GenericEnum,
|
|
GenericStruct,
|
|
GenericClass,
|
|
GenericActor,
|
|
GenericDistributedActor,
|
|
GenericType,
|
|
Subscript,
|
|
StaticSubscript,
|
|
ClassSubscript,
|
|
Constructor,
|
|
Destructor,
|
|
LocalFunction,
|
|
GlobalFunction,
|
|
OperatorFunction,
|
|
Method,
|
|
StaticMethod,
|
|
ClassMethod,
|
|
DistributedMethod,
|
|
Getter,
|
|
Setter,
|
|
InitAccessor,
|
|
Addressor,
|
|
MutableAddressor,
|
|
ReadAccessor,
|
|
ModifyAccessor,
|
|
WillSet,
|
|
DidSet,
|
|
EnumElement,
|
|
Module,
|
|
Missing,
|
|
MissingMember,
|
|
Requirement,
|
|
OpaqueResultType,
|
|
OpaqueVarType,
|
|
Macro,
|
|
MacroExpansion,
|
|
Using
|
|
};
|
|
|
|
/// Describes which spelling was used in the source for the 'static' or 'class'
|
|
/// keyword.
|
|
enum class StaticSpellingKind : uint8_t {
|
|
None,
|
|
KeywordStatic,
|
|
KeywordClass,
|
|
};
|
|
|
|
/// Keeps track of whether an enum has cases that have associated values.
|
|
enum class AssociatedValueCheck {
|
|
/// We have not yet checked.
|
|
Unchecked,
|
|
/// The enum contains no cases or all cases contain no associated values.
|
|
NoAssociatedValues,
|
|
/// The enum contains at least one case with associated values.
|
|
HasAssociatedValues,
|
|
};
|
|
|
|
/// An explicit declaration of the safety of
|
|
enum class ExplicitSafety {
|
|
/// There was no explicit declaration of the safety of the given entity.
|
|
Unspecified,
|
|
/// The entity was explicitly declared safe with @safe.
|
|
Safe,
|
|
/// The entity was explicitly declared unsafe with @unsafe.
|
|
Unsafe
|
|
};
|
|
|
|
/// Diagnostic printing of \c StaticSpellingKind.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK);
|
|
|
|
/// Diagnostic printing of \c ReferenceOwnership.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceOwnership RO);
|
|
|
|
enum class SelfAccessKind : uint8_t {
|
|
NonMutating,
|
|
Mutating,
|
|
LegacyConsuming,
|
|
Consuming,
|
|
Borrowing,
|
|
LastSelfAccessKind = Borrowing,
|
|
};
|
|
enum : unsigned {
|
|
NumSelfAccessKindBits =
|
|
countBitsUsed(static_cast<unsigned>(SelfAccessKind::LastSelfAccessKind))
|
|
};
|
|
static_assert(uint8_t(SelfAccessKind::LastSelfAccessKind) <
|
|
(NumSelfAccessKindBits << 1),
|
|
"Self Access Kind is too small to fit in SelfAccess kind bits. "
|
|
"Please expand ");
|
|
|
|
enum class UsingSpecifier : uint8_t {
|
|
MainActor,
|
|
Nonisolated,
|
|
LastSpecifier = Nonisolated,
|
|
};
|
|
enum : unsigned {
|
|
NumUsingSpecifierBits =
|
|
countBitsUsed(static_cast<unsigned>(UsingSpecifier::LastSpecifier))
|
|
};
|
|
|
|
/// Diagnostic printing of \c SelfAccessKind.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK);
|
|
|
|
/// Encapsulation of the overload signature of a given declaration,
|
|
/// which is used to determine uniqueness of a declaration within a
|
|
/// given context.
|
|
///
|
|
/// Two definitions in the same context may not have the same overload
|
|
/// signature.
|
|
struct OverloadSignature {
|
|
/// The full name of the declaration.
|
|
DeclName Name;
|
|
|
|
/// The kind of unary operator.
|
|
UnaryOperatorKind UnaryOperator;
|
|
|
|
/// Whether this is an instance member.
|
|
unsigned IsInstanceMember : 1;
|
|
|
|
/// Whether this is a variable.
|
|
unsigned IsVariable : 1;
|
|
|
|
/// Whether this is a function.
|
|
unsigned IsFunction : 1;
|
|
|
|
/// Whether this is an async function.
|
|
unsigned IsAsyncFunction : 1;
|
|
|
|
/// Whether this is an distributed function.
|
|
unsigned IsDistributed : 1;
|
|
|
|
/// Whether this is a enum element.
|
|
unsigned IsEnumElement : 1;
|
|
|
|
/// Whether this is a nominal type.
|
|
unsigned IsNominal : 1;
|
|
|
|
/// Whether this is a type alias.
|
|
unsigned IsTypeAlias : 1;
|
|
|
|
/// Whether this is a macro.
|
|
unsigned IsMacro : 1;
|
|
|
|
/// Whether this is a generic argument.
|
|
unsigned IsGenericArg : 1;
|
|
|
|
/// Whether this signature is part of a protocol extension.
|
|
unsigned InProtocolExtension : 1;
|
|
|
|
/// Whether this signature is of a member defined in an extension of a generic
|
|
/// type.
|
|
unsigned InExtensionOfGenericType : 1;
|
|
|
|
/// Whether this declaration has an opaque return type.
|
|
unsigned HasOpaqueReturnType : 1;
|
|
|
|
OverloadSignature()
|
|
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
|
|
IsVariable(false), IsFunction(false), IsAsyncFunction(false),
|
|
IsDistributed(false), IsEnumElement(false), IsNominal(false),
|
|
IsTypeAlias(false), IsMacro(false), IsGenericArg(false),
|
|
InProtocolExtension(false), InExtensionOfGenericType(false),
|
|
HasOpaqueReturnType(false) { }
|
|
};
|
|
|
|
/// Determine whether two overload signatures conflict.
|
|
///
|
|
/// \param sig1 The overload signature of the first declaration.
|
|
/// \param sig2 The overload signature of the second declaration.
|
|
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
|
|
/// will be allowed to conflict with members of protocol declarations.
|
|
bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2,
|
|
bool skipProtocolExtensionCheck = false);
|
|
|
|
/// Determine whether two overload signatures and overload types conflict.
|
|
///
|
|
/// \param ctx The AST context.
|
|
/// \param sig1 The overload signature of the first declaration.
|
|
/// \param sig1Type The overload type of the first declaration.
|
|
/// \param sig2 The overload signature of the second declaration.
|
|
/// \param sig2Type The overload type of the second declaration.
|
|
/// \param wouldConflictInSwift5 If non-null, the referenced boolean will be set
|
|
/// to \c true iff the function returns \c false for this version of
|
|
/// Swift, but the given overloads will conflict in Swift 5 mode.
|
|
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
|
|
/// will be allowed to conflict with members of protocol declarations.
|
|
bool conflicting(ASTContext &ctx,
|
|
const OverloadSignature& sig1, CanType sig1Type,
|
|
const OverloadSignature& sig2, CanType sig2Type,
|
|
bool *wouldConflictInSwift5 = nullptr,
|
|
bool skipProtocolExtensionCheck = false);
|
|
|
|
/// The kind of artificial main to generate.
|
|
enum class ArtificialMainKind : uint8_t {
|
|
NSApplicationMain,
|
|
UIApplicationMain,
|
|
TypeMain,
|
|
};
|
|
|
|
/// Decl - Base class for all declarations in Swift.
|
|
class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public SwiftObjectHeader {
|
|
protected:
|
|
// clang-format off
|
|
//
|
|
// We format these different than clang-format wishes us to... so turn if off
|
|
// for the inline bitfields.
|
|
union { uint64_t OpaqueBits;
|
|
|
|
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1+1+1+1+1+1+1+1,
|
|
Kind : bitmax(NumDeclKindBits,8),
|
|
|
|
/// Whether this declaration is invalid.
|
|
Invalid : 1,
|
|
|
|
/// Whether this declaration was implicitly created, e.g.,
|
|
/// an implicit constructor in a struct.
|
|
Implicit : 1,
|
|
|
|
/// Whether this declaration was mapped directly from a Clang AST.
|
|
///
|
|
/// Use getClangNode() to retrieve the corresponding Clang AST.
|
|
FromClang : 1,
|
|
|
|
/// Whether this declaration is syntactically scoped inside of
|
|
/// a local context, but should behave like a top-level
|
|
/// declaration for name lookup purposes. This is used by
|
|
/// lldb.
|
|
Hoisted : 1,
|
|
|
|
/// Whether the set of semantic attributes has been computed.
|
|
SemanticAttrsComputed : 1,
|
|
|
|
/// True if \c ObjCInterfaceAndImplementationRequest has been computed
|
|
/// and did \em not find anything. This is the fast path where we can bail
|
|
/// out without checking other caches or computing anything.
|
|
LacksObjCInterfaceOrImplementation : 1,
|
|
|
|
/// True if we're in the common case where the ExpandMemberAttributeMacros
|
|
/// request returned an empty array.
|
|
NoMemberAttributeMacros : 1,
|
|
|
|
/// True if we're in the common case where the ExpandPeerMacroRequest
|
|
/// request returned an empty array.
|
|
NoPeerMacros : 1,
|
|
|
|
/// True if we're in the common case where the GlobalActorAttributeRequest
|
|
/// request returned a pair of null pointers.
|
|
NoGlobalActorAttribute : 1,
|
|
|
|
/// True if we're in the common case where the SPIGroupsRequest
|
|
/// request returned an empty array of identifiers.
|
|
NoSPIGroups : 1,
|
|
|
|
/// True if we have computed whether this declaration is unsafe.
|
|
IsUnsafeComputed : 1,
|
|
|
|
/// True if this declaration has been determined to be "unsafe".
|
|
IsUnsafe : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+1+2+16,
|
|
/// Whether this pattern binding declares static variables.
|
|
IsStatic : 1,
|
|
|
|
/// Whether this pattern binding is synthesized by the debugger.
|
|
IsDebugger : 1,
|
|
|
|
/// Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
: NumPadBits,
|
|
|
|
/// The number of pattern binding declarations.
|
|
NumPatternEntries : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(EnumCaseDecl, Decl, 32,
|
|
: NumPadBits,
|
|
|
|
/// The number of tail-allocated element pointers.
|
|
NumElements : 32
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ValueDecl, Decl, 1+1+1+1,
|
|
AlreadyInLookupTable : 1,
|
|
|
|
/// Whether we have already checked whether this declaration is a
|
|
/// redeclaration.
|
|
CheckedRedeclaration : 1,
|
|
|
|
/// Whether the decl can be accessed by swift users; for instance,
|
|
/// a.storage for lazy var a is a decl that cannot be accessed.
|
|
IsUserAccessible : 1,
|
|
|
|
/// Whether this member was synthesized as part of a derived
|
|
/// protocol conformance.
|
|
Synthesized : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AbstractStorageDecl, ValueDecl, 1,
|
|
/// Whether this property is a type property (currently unfortunately
|
|
/// called 'static').
|
|
IsStatic : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 2+1+1+1+1+1+1+1,
|
|
/// Encodes whether this is a 'let' binding.
|
|
Introducer : 2,
|
|
|
|
/// Whether this declaration captures the 'self' param under the same name.
|
|
IsSelfParamCapture : 1,
|
|
|
|
/// Whether this is a property used in expressions in the debugger.
|
|
/// It is up to the debugger to instruct SIL how to access this variable.
|
|
IsDebuggerVar : 1,
|
|
|
|
/// Whether this is the backing storage for a lazy property.
|
|
IsLazyStorageProperty : 1,
|
|
|
|
/// Whether this is the backing storage for a property wrapper.
|
|
IsPropertyWrapperBackingProperty : 1,
|
|
|
|
/// Whether this is a lazily top-level global variable from the main file.
|
|
IsTopLevelGlobal : 1,
|
|
|
|
/// Whether this variable has no attached property wrappers.
|
|
NoAttachedPropertyWrappers : 1,
|
|
|
|
/// Whether this variable has no property wrapper auxiliary variables.
|
|
NoPropertyWrapperAuxiliaryVariables : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1+2+NumDefaultArgumentKindBits,
|
|
/// The specifier associated with this parameter + 1, or zero if the
|
|
/// specifier has not been computed yet. This determines
|
|
/// the ownership semantics of the parameter.
|
|
OwnershipSpecifier : 3,
|
|
|
|
/// Information about a symbolic default argument, like #file.
|
|
defaultArgumentKind : NumDefaultArgumentKindBits
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
|
|
StaticSpelling : 2
|
|
);
|
|
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+2+2+2+8+1+1+1+1+1+1,
|
|
/// \see AbstractFunctionDecl::BodyKind
|
|
BodyKind : 3,
|
|
|
|
/// \see AbstractFunctionDecl::BodySkippedStatus
|
|
BodySkippedStatus : 2,
|
|
|
|
/// \see AbstractFunctionDecl::BodyExpandedStatus
|
|
BodyExpandedStatus : 2,
|
|
|
|
/// \see AbstractFunctionDecl::SILSynthesizeKind
|
|
SILSynthesizeKind : 2,
|
|
|
|
/// Import as member status.
|
|
IAMStatus : 8,
|
|
|
|
/// Whether the function has an implicit 'self' parameter.
|
|
HasImplicitSelfDecl : 1,
|
|
|
|
/// Whether we are overridden later.
|
|
Overridden : 1,
|
|
|
|
/// Whether the function is async.
|
|
Async : 1,
|
|
|
|
/// Whether the function body throws.
|
|
Throws : 1,
|
|
|
|
/// Whether peeking into this function detected nested type declarations.
|
|
/// This is set when skipping over the decl at parsing.
|
|
HasNestedTypeDeclarations : 1,
|
|
|
|
/// Whether this function is a distributed thunk for a distributed
|
|
/// function or computed property.
|
|
DistributedThunk : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl,
|
|
1+1+2+1+1+NumSelfAccessKindBits+1+1,
|
|
/// Whether we've computed the 'static' flag yet.
|
|
IsStaticComputed : 1,
|
|
|
|
/// Whether this function is a 'static' method.
|
|
IsStatic : 1,
|
|
|
|
/// Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
/// Whether we are statically dispatched even if overridable
|
|
ForcedStaticDispatch : 1,
|
|
|
|
/// Whether we've computed the 'self' access kind yet.
|
|
SelfAccessComputed : 1,
|
|
|
|
/// Backing bits for 'self' access kind.
|
|
SelfAccess : NumSelfAccessKindBits,
|
|
|
|
/// Whether this is a top-level function which should be treated
|
|
/// as if it were in local context for the purposes of capture
|
|
/// analysis.
|
|
HasTopLevelLocalContextCaptures : 1,
|
|
|
|
/// Set to true if this FuncDecl has a 'sending' result.
|
|
HasSendingResult : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4 + 1 + 1,
|
|
/// The kind of accessor this is.
|
|
AccessorKind : 4,
|
|
|
|
/// Whether the accessor is transparent.
|
|
IsTransparent : 1,
|
|
|
|
/// Whether we have computed the above.
|
|
IsTransparentComputed : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 1+1,
|
|
/// Whether this constructor can fail, by building an Optional type.
|
|
Failable : 1,
|
|
|
|
/// Whether this initializer is a stub placed into a subclass to
|
|
/// catch invalid delegations to a designated initializer not
|
|
/// overridden by the subclass. A stub will always trap at runtime.
|
|
///
|
|
/// Initializer stubs can be invoked from Objective-C or through
|
|
/// the Objective-C runtime; there is no way to directly express
|
|
/// an object construction that will invoke a stub.
|
|
HasStubImplementation : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_EMPTY(TypeDecl, ValueDecl);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, TypeDecl, 16+16+3+1,
|
|
Depth : 16,
|
|
Index : 16,
|
|
ParamKind : 3,
|
|
|
|
/// Whether this generic parameter represents an opaque type.
|
|
IsOpaqueType : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(AssociatedTypeDecl, TypeDecl, 1,
|
|
/// Whether we have computed the default type.
|
|
IsDefaultDefinitionTypeComputed : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_EMPTY(GenericTypeDecl, TypeDecl);
|
|
|
|
SWIFT_INLINE_BITFIELD(TypeAliasDecl, GenericTypeDecl, 1+1,
|
|
/// Whether the typealias forwards perfectly to its underlying type.
|
|
IsCompatibilityAlias : 1,
|
|
/// Whether this was a global typealias synthesized by the debugger.
|
|
IsDebuggerAlias : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1+1,
|
|
/// Whether we have already added implicitly-defined initializers
|
|
/// to this declaration.
|
|
AddedImplicitInitializers : 1,
|
|
|
|
/// Whether there is are lazily-loaded conformances for this nominal type.
|
|
HasLazyConformances : 1,
|
|
|
|
/// Whether this nominal type is having its semantic members resolved.
|
|
IsComputingSemanticMembers : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8,
|
|
/// Whether the \c RequiresClass bit is valid.
|
|
RequiresClassValid : 1,
|
|
|
|
/// Whether this is a class-bounded protocol.
|
|
RequiresClass : 1,
|
|
|
|
/// Whether the \c ExistentialConformsToSelf bit is valid.
|
|
ExistentialConformsToSelfValid : 1,
|
|
|
|
/// Whether the existential of this protocol conforms to itself.
|
|
ExistentialConformsToSelf : 1,
|
|
|
|
/// Whether the \c HasSelfOrAssociatedTypeRequirements bit is valid.
|
|
HasSelfOrAssociatedTypeRequirementsValid : 1,
|
|
|
|
/// Whether this protocol has \c Self or associated type requirements.
|
|
/// See \c hasSelfOrAssociatedTypeRequirements() for clarification.
|
|
HasSelfOrAssociatedTypeRequirements : 1,
|
|
|
|
/// True if the protocol has requirements that cannot be satisfied (e.g.
|
|
/// because they could not be imported from Objective-C).
|
|
HasMissingRequirements : 1,
|
|
|
|
/// Whether we've computed the InheritedProtocolsRequest.
|
|
InheritedProtocolsValid : 1,
|
|
|
|
/// Whether we've computed the AllInheritedProtocolsRequest.
|
|
AllInheritedProtocolsValid : 1,
|
|
|
|
/// Whether we have computed a requirement signature.
|
|
HasRequirementSignature : 1,
|
|
|
|
/// Whether we have a lazy-loaded requirement signature.
|
|
HasLazyRequirementSignature : 1,
|
|
|
|
/// Whether we have computed the list of associated types.
|
|
HasAssociatedTypes : 1,
|
|
|
|
/// Whether we have a lazy-loaded list of associated types.
|
|
HasLazyAssociatedTypes : 1,
|
|
|
|
/// Whether we have a lazy-loaded list of primary associated types.
|
|
HasLazyPrimaryAssociatedTypes : 1,
|
|
|
|
/// Whether we've computed the protocol requirements list yet.
|
|
ProtocolRequirementsValid : 1,
|
|
|
|
: NumPadBits,
|
|
|
|
/// If this is a compiler-known protocol, this will be a KnownProtocolKind
|
|
/// value, plus one. Otherwise, it will be 0.
|
|
KnownProtocol : 8 // '8' for speed. This only needs 6.
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+1+2+1+1+1+1+1+1,
|
|
/// Whether this class inherits its superclass's convenience initializers.
|
|
InheritsSuperclassInits : 1,
|
|
ComputedInheritsSuperclassInits : 1,
|
|
|
|
/// \see ClassDecl::ForeignKind
|
|
RawForeignKind : 2,
|
|
|
|
HasMissingDesignatedInitializers : 1,
|
|
ComputedHasMissingDesignatedInitializers : 1,
|
|
|
|
HasMissingVTableEntries : 1,
|
|
ComputedHasMissingVTableEntries : 1,
|
|
|
|
/// Whether instances of this class are incompatible
|
|
/// with weak and unowned references.
|
|
IsIncompatibleWithWeakReferences : 1,
|
|
|
|
/// Set when the class represents an actor
|
|
IsActor : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1 + 1 + 1,
|
|
/// True if this struct has storage for fields that
|
|
/// aren't accessible in Swift.
|
|
HasUnreferenceableStorage : 1,
|
|
/// True if this struct is imported from C++ and does
|
|
/// not have trivial value witness functions.
|
|
IsCxxNonTrivial : 1,
|
|
/// True if this struct is imported from C and has
|
|
/// address diversified ptrauth qualified field.
|
|
IsNonTrivialPtrAuth : 1);
|
|
|
|
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+1+1,
|
|
/// True if the enum has cases and at least one case has associated values.
|
|
HasAssociatedValues : 2,
|
|
/// True if the enum has at least one case that has some availability
|
|
/// attribute. A single bit because it's lazily computed along with the
|
|
/// HasAssociatedValues bit.
|
|
HasAnyUnavailableValues : 1,
|
|
/// True if \c isAvailableDuringLowering() is false for any cases. Lazily
|
|
/// computed along with HasAssociatedValues.
|
|
HasAnyUnavailableDuringLoweringValues : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+8,
|
|
/// If the module is compiled as static library.
|
|
StaticLibrary : 1,
|
|
|
|
/// If the module was or is being compiled with `-enable-testing`.
|
|
TestingEnabled : 1,
|
|
|
|
/// If the module failed to load
|
|
FailedToLoad : 1,
|
|
|
|
/// Whether the module is resilient.
|
|
///
|
|
/// \sa ResilienceStrategy
|
|
RawResilienceStrategy : 1,
|
|
|
|
/// Whether the module was rebuilt from a module interface instead of being
|
|
/// build from the full source.
|
|
IsBuiltFromInterface : 1,
|
|
|
|
/// Whether all imports have been resolved. Used to detect circular imports.
|
|
HasResolvedImports : 1,
|
|
|
|
/// If the module was or is being compiled with `-enable-private-imports`.
|
|
PrivateImportsEnabled : 1,
|
|
|
|
/// If the module is compiled with `-enable-implicit-dynamic`.
|
|
ImplicitDynamicEnabled : 1,
|
|
|
|
/// Whether the module is a system module.
|
|
IsSystemModule : 1,
|
|
|
|
/// Whether the module was imported from Clang (or, someday, maybe another
|
|
/// language).
|
|
IsNonSwiftModule : 1,
|
|
|
|
/// Whether this module is the main module.
|
|
IsMainModule : 1,
|
|
|
|
/// Whether this module has incremental dependency information available.
|
|
HasIncrementalInfo : 1,
|
|
|
|
/// Whether this module was built with -experimental-hermetic-seal-at-link.
|
|
HasHermeticSealAtLink : 1,
|
|
|
|
/// Whether this module was built with embedded Swift.
|
|
IsEmbeddedSwiftModule : 1,
|
|
|
|
/// Whether this module has been compiled with comprehensive checking for
|
|
/// concurrency, e.g., Sendable checking.
|
|
IsConcurrencyChecked : 1,
|
|
|
|
/// If the map from @objc provided name to top level swift::Decl in this
|
|
/// module is populated
|
|
ObjCNameLookupCachePopulated : 1,
|
|
|
|
/// Whether this module has been built with C++ interoperability enabled.
|
|
HasCxxInteroperability : 1,
|
|
|
|
/// Whether this module uses the platform default C++ stdlib, or an
|
|
/// overridden C++ stdlib.
|
|
CXXStdlibKind : 8,
|
|
|
|
/// Whether this module has been built with -allow-non-resilient-access.
|
|
AllowNonResilientAccess : 1,
|
|
|
|
/// Whether this module has been built with -package-cmo.
|
|
SerializePackageEnabled : 1,
|
|
|
|
/// Whether this module has enabled strict memory safety checking.
|
|
StrictMemorySafety : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,
|
|
/// Is this an assignment operator?
|
|
IsAssignment : 1,
|
|
|
|
/// The group's associativity. A value of the Associativity enum.
|
|
Associativity : 2
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ImportDecl, Decl, 3+8,
|
|
ImportKind : 3,
|
|
|
|
/// The number of elements in this path.
|
|
NumPathElements : 8
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(UsingDecl, Decl, NumUsingSpecifierBits,
|
|
Specifier : NumUsingSpecifierBits
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ExtensionDecl, Decl, 4+1,
|
|
/// An encoding of the default and maximum access level for this extension.
|
|
/// The value 4 corresponds to AccessLevel::Public
|
|
///
|
|
/// This is encoded as (1 << (maxAccess-1)) | (1 << (defaultAccess-1)),
|
|
/// which works because the maximum is always greater than or equal to the
|
|
/// default, and 'private' is never used. 0 represents an uncomputed value.
|
|
DefaultAndMaxAccessLevel : 4,
|
|
|
|
/// Whether there is are lazily-loaded conformances for this extension.
|
|
HasLazyConformances : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(MissingMemberDecl, Decl, 1+2,
|
|
NumberOfFieldOffsetVectorEntries : 1,
|
|
NumberOfVTableEntries : 2
|
|
);
|
|
|
|
} Bits;
|
|
// Turn back on clang-format now that we have defined our inline bitfields.
|
|
// clang-format on
|
|
|
|
// Storage for the declaration attributes.
|
|
DeclAttributes Attrs;
|
|
|
|
/// The next declaration in the list of declarations within this
|
|
/// member context.
|
|
Decl *NextDecl = nullptr;
|
|
|
|
friend class DeclIterator;
|
|
friend class IterableDeclContext;
|
|
friend class MemberLookupTable;
|
|
friend class DeclDeserializer;
|
|
friend class RawCommentRequest;
|
|
friend class ExpandMemberAttributeMacros;
|
|
friend class ExpandPeerMacroRequest;
|
|
friend class GlobalActorAttributeRequest;
|
|
friend class SPIGroupsRequest;
|
|
|
|
private:
|
|
llvm::PointerUnion<DeclContext *, ASTContext *> Context;
|
|
|
|
Decl(const Decl&) = delete;
|
|
void operator=(const Decl&) = delete;
|
|
SourceLoc getLocFromSource() const;
|
|
|
|
static SwiftMetatype getDeclMetatype(DeclKind kind);
|
|
|
|
/// Returns the serialized locations of this declaration from the
|
|
/// corresponding .swiftsourceinfo file. "Empty" (ie. \c BufferID of 0, an
|
|
/// invalid \c Loc, and empty \c DocRanges) if either there is no
|
|
/// .swiftsourceinfo or the buffer could not be created, eg. if the file
|
|
/// no longer exists.
|
|
const ExternalSourceLocs *getSerializedLocs() const;
|
|
|
|
/// Directly set the invalid bit
|
|
void setInvalidBit();
|
|
|
|
bool hasNoMemberAttributeMacros() const {
|
|
return Bits.Decl.NoMemberAttributeMacros;
|
|
}
|
|
|
|
void setHasNoMemberAttributeMacros() {
|
|
Bits.Decl.NoMemberAttributeMacros = true;
|
|
}
|
|
|
|
bool hasNoPeerMacros() const {
|
|
return Bits.Decl.NoPeerMacros;
|
|
}
|
|
|
|
void setHasNoPeerMacros() {
|
|
Bits.Decl.NoPeerMacros = true;
|
|
}
|
|
|
|
bool hasNoGlobalActorAttribute() const {
|
|
return Bits.Decl.NoGlobalActorAttribute;
|
|
}
|
|
|
|
void setHasNoGlobalActorAttribute() {
|
|
Bits.Decl.NoGlobalActorAttribute = true;
|
|
}
|
|
|
|
bool hasNoSPIGroups() const {
|
|
return Bits.Decl.NoSPIGroups;
|
|
}
|
|
|
|
void setHasNoSPIGroups() {
|
|
Bits.Decl.NoSPIGroups = true;
|
|
}
|
|
|
|
protected:
|
|
|
|
Decl(DeclKind kind, llvm::PointerUnion<DeclContext *, ASTContext *> context)
|
|
: SwiftObjectHeader(getDeclMetatype(kind)), Context(context) {
|
|
Bits.OpaqueBits = 0;
|
|
Bits.Decl.Kind = unsigned(kind);
|
|
Bits.Decl.Invalid = false;
|
|
Bits.Decl.Implicit = false;
|
|
Bits.Decl.FromClang = false;
|
|
Bits.Decl.Hoisted = false;
|
|
Bits.Decl.LacksObjCInterfaceOrImplementation = false;
|
|
Bits.Decl.NoMemberAttributeMacros = false;
|
|
Bits.Decl.NoGlobalActorAttribute = false;
|
|
Bits.Decl.NoSPIGroups = false;
|
|
Bits.Decl.IsUnsafeComputed = false;
|
|
Bits.Decl.IsUnsafe = false;
|
|
}
|
|
|
|
/// Get the Clang node associated with this declaration.
|
|
ClangNode getClangNodeImpl() const;
|
|
|
|
/// Set the Clang node associated with this declaration.
|
|
void setClangNode(ClangNode Node);
|
|
|
|
void updateClangNode(ClangNode node) {
|
|
assert(hasClangNode());
|
|
setClangNode(node);
|
|
}
|
|
friend class ClangImporter;
|
|
|
|
DeclContext *getDeclContextForModule() const;
|
|
|
|
public:
|
|
DeclKind getKind() const { return DeclKind(Bits.Decl.Kind); }
|
|
|
|
/// Retrieve the name of the given declaration kind.
|
|
///
|
|
/// This name should only be used for debugging dumps and other
|
|
/// developer aids, and should never be part of a diagnostic or exposed
|
|
/// to the user of the compiler in any way.
|
|
static StringRef getKindName(DeclKind K);
|
|
|
|
/// Retrieve the descriptive kind for this declaration.
|
|
DescriptiveDeclKind getDescriptiveKind() const;
|
|
|
|
/// Produce a name for the given descriptive declaration kind, which
|
|
/// is suitable for use in diagnostics.
|
|
static StringRef getDescriptiveKindName(DescriptiveDeclKind K);
|
|
|
|
/// Whether swift users should be able to access this decl. For instance,
|
|
/// var a.storage for lazy var a is an inaccessible decl. An inaccessible decl
|
|
/// has to be implicit; but an implicit decl does not have to be inaccessible,
|
|
/// for instance, self.
|
|
bool isUserAccessible() const;
|
|
|
|
/// Determine if the decl can have a comment. If false, a comment will
|
|
/// not be serialized.
|
|
bool canHaveComment() const;
|
|
|
|
LLVM_READONLY
|
|
DeclContext *getDeclContext() const {
|
|
if (auto dc = Context.dyn_cast<DeclContext *>())
|
|
return dc;
|
|
|
|
return getDeclContextForModule();
|
|
}
|
|
void setDeclContext(DeclContext *DC);
|
|
|
|
/// Retrieve the innermost declaration context corresponding to this
|
|
/// declaration, which will either be the declaration itself (if it's
|
|
/// also a declaration context) or its declaration context.
|
|
DeclContext *getInnermostDeclContext() const;
|
|
|
|
/// Retrieve the module in which this declaration resides.
|
|
LLVM_READONLY
|
|
ModuleDecl *getModuleContext() const;
|
|
|
|
/// Retrieve the module in which this declaration would be found by name
|
|
/// lookup queries. The result can differ from that of `getModuleContext()`
|
|
/// when the decl was imported via Cxx interop.
|
|
LLVM_READONLY
|
|
ModuleDecl *getModuleContextForNameLookup() const;
|
|
|
|
/// getASTContext - Return the ASTContext that this decl lives in.
|
|
LLVM_READONLY
|
|
ASTContext &getASTContext() const {
|
|
if (auto dc = Context.dyn_cast<DeclContext *>())
|
|
return dc->getASTContext();
|
|
|
|
return *Context.get<ASTContext *>();
|
|
}
|
|
|
|
const DeclAttributes &getAttrs() const {
|
|
return Attrs;
|
|
}
|
|
|
|
DeclAttributes &getAttrs() {
|
|
return Attrs;
|
|
}
|
|
|
|
/// Returns the attributes that were directly attached to this declaration
|
|
/// as written in source, ie. does not include semantic attributes or ones
|
|
/// generated by macro expansions.
|
|
ParsedDeclAttributes getParsedAttrs() const;
|
|
|
|
/// Returns the attributes attached to this declaration,
|
|
/// including attributes that are generated as the result of member
|
|
/// attribute macro expansion.
|
|
DeclAttributes getExpandedAttrs() const;
|
|
|
|
/// Returns all semantic attributes attached to this declaration,
|
|
/// including attributes that are generated as the result of member
|
|
/// attribute macro expansion.
|
|
DeclAttributes getSemanticAttrs() const;
|
|
|
|
/// Register the relationship between \c this and \p attr->abiDecl , assuming
|
|
/// that \p attr is attached to \c this . This is necessary for
|
|
/// \c ABIRoleInfo::ABIRoleInfo() to determine that \c attr->abiDecl
|
|
/// is ABI-only and locate its API counterpart.
|
|
void recordABIAttr(ABIAttr *attr);
|
|
|
|
/// Set this declaration's attributes to the specified attribute list,
|
|
/// applying any post-processing logic appropriate for attributes parsed
|
|
/// from source code.
|
|
void attachParsedAttrs(DeclAttributes attrs);
|
|
|
|
/// Retrieve the custom name in the \c @objc attribute, if present.
|
|
std::optional<ObjCSelector>
|
|
getExplicitObjCName(bool allowInvalid = false) const;
|
|
|
|
/// True if this declaration provides an implementation for an imported
|
|
/// Objective-C declaration. This implies various restrictions and special
|
|
/// behaviors for it and, if it's an extension, its members.
|
|
bool isObjCImplementation() const;
|
|
|
|
using AuxiliaryDeclCallback = llvm::function_ref<void(Decl *)>;
|
|
|
|
/// Iterate over the auxiliary declarations for this declaration,
|
|
/// invoking the given callback with each auxiliary decl.
|
|
///
|
|
/// Auxiliary declarations can be property wrapper backing variables,
|
|
/// backing variables for 'lazy' vars, or peer macro expansions.
|
|
///
|
|
/// When \p visitFreestandingExpanded is true (the default), this will also
|
|
/// visit the declarations produced by a freestanding macro expansion.
|
|
void visitAuxiliaryDecls(
|
|
AuxiliaryDeclCallback callback,
|
|
bool visitFreestandingExpanded = true
|
|
) const;
|
|
|
|
using MacroCallback = llvm::function_ref<void(CustomAttr *, MacroDecl *)>;
|
|
|
|
/// Iterate over each attached macro with the given role, invoking the
|
|
/// given callback with each macro custom attribute and corresponding macro
|
|
/// declaration.
|
|
void forEachAttachedMacro(MacroRole role, MacroCallback) const;
|
|
|
|
/// Returns the resolved macro for the given custom attribute
|
|
/// attached to this declaration.
|
|
MacroDecl *getResolvedMacro(CustomAttr *attr) const;
|
|
|
|
/// Retrieve the discriminator for the given custom attribute that names
|
|
/// an attached macro.
|
|
unsigned getAttachedMacroDiscriminator(DeclBaseName macroName, MacroRole role,
|
|
const CustomAttr *attr) const;
|
|
|
|
/// Returns the resolved type for the give custom attribute attached to this
|
|
/// declaration.
|
|
Type getResolvedCustomAttrType(CustomAttr *attr) const;
|
|
|
|
/// Determines if this declaration is exposed to clients of the module it is
|
|
/// defined in. For example, `public` declarations are exposed to clients.
|
|
bool isExposedToClients() const;
|
|
|
|
/// Returns the innermost enclosing decl with an availability annotation.
|
|
const Decl *getInnermostDeclWithAvailability() const;
|
|
|
|
/// Returns the introduced OS version in the given platform kind specified
|
|
/// by @available attribute.
|
|
/// This function won't consider the parent context to get the information.
|
|
std::optional<llvm::VersionTuple>
|
|
getIntroducedOSVersion(PlatformKind Kind) const;
|
|
|
|
/// Returns the OS version in which the decl became ABI as specified by the
|
|
/// `@backDeployed` attribute.
|
|
std::optional<llvm::VersionTuple>
|
|
getBackDeployedBeforeOSVersion(ASTContext &Ctx,
|
|
bool forTargetVariant = false) const;
|
|
|
|
/// Returns true if the decl has an active `@backDeployed` attribute for the
|
|
/// given context.
|
|
bool isBackDeployed(ASTContext &Ctx) const;
|
|
|
|
/// Returns the starting location of the entire declaration.
|
|
SourceLoc getStartLoc() const { return getSourceRange().Start; }
|
|
|
|
/// Returns the end location of the entire declaration.
|
|
SourceLoc getEndLoc() const { return getSourceRange().End; }
|
|
|
|
/// Returns the preferred location when referring to declarations
|
|
/// in diagnostics.
|
|
SourceLoc getLoc(bool SerializedOK = true) const;
|
|
|
|
/// Returns the source range of the entire declaration.
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Returns the source range of the declaration including its attributes.
|
|
SourceRange getSourceRangeIncludingAttrs() const;
|
|
|
|
/// Retrieve the location at which we should insert a new attribute or
|
|
/// modifier.
|
|
SourceLoc getAttributeInsertionLoc(bool forModifier) const;
|
|
|
|
using ImportAccessLevel = std::optional<AttributedImport<ImportedModule>>;
|
|
|
|
/// Returns the import that may restrict the access to this decl
|
|
/// from \p useDC.
|
|
///
|
|
/// If this decl and \p useDC are from the same module it returns
|
|
/// \c std::nullopt. If there are many imports, it returns the most
|
|
/// permissive one.
|
|
ImportAccessLevel getImportAccessFrom(const DeclContext *useDC) const;
|
|
|
|
SourceLoc TrailingSemiLoc;
|
|
|
|
/// Whether this declaration is within a macro expansion relative to
|
|
/// its decl context. If the decl context is itself in a macro expansion,
|
|
/// the method returns \c true if this decl is in a different macro
|
|
/// expansion buffer than the context.
|
|
///
|
|
/// \Note this method returns \c false if this declaration was
|
|
/// constructed from a serialized module.
|
|
bool isInMacroExpansionInContext() const;
|
|
|
|
/// Whether this declaration is within a macro expansion relative to
|
|
/// its decl context, and the macro was attached to a node imported from clang.
|
|
bool isInMacroExpansionFromClangHeader() const;
|
|
|
|
/// Returns the appropriate kind of entry point to generate for this class,
|
|
/// based on its attributes.
|
|
///
|
|
/// It is an error to call this on a type that does not have either an
|
|
/// *ApplicationMain or an main attribute.
|
|
ArtificialMainKind getArtificialMainKind() const;
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
SWIFT_DEBUG_DUMPER(dump(const char *filename));
|
|
void dump(raw_ostream &OS, unsigned Indent = 0) const;
|
|
|
|
/// Pretty-print the given declaration.
|
|
///
|
|
/// \param OS Output stream to which the declaration will be printed.
|
|
void print(raw_ostream &OS) const;
|
|
void print(raw_ostream &OS, const PrintOptions &Opts) const;
|
|
|
|
void printInherited(ASTPrinter &Printer, const PrintOptions &Options) const;
|
|
|
|
/// Pretty-print the given declaration.
|
|
///
|
|
/// \param Printer ASTPrinter object.
|
|
///
|
|
/// \param Opts Options to control how pretty-printing is performed.
|
|
///
|
|
/// \returns true if the declaration was printed or false if the print options
|
|
/// required the declaration to be skipped from printing.
|
|
bool print(ASTPrinter &Printer, const PrintOptions &Opts) const;
|
|
|
|
/// Determine whether this declaration should be printed when
|
|
/// encountered in its declaration context's list of members.
|
|
bool shouldPrintInContext(const PrintOptions &PO) const;
|
|
|
|
bool walk(ASTWalker &walker);
|
|
|
|
/// Return whether this declaration has been determined invalid.
|
|
bool isInvalid() const;
|
|
|
|
/// Mark this declaration invalid.
|
|
void setInvalid();
|
|
|
|
/// Determine whether this declaration was implicitly generated by the
|
|
/// compiler (rather than explicitly written in source code).
|
|
bool isImplicit() const { return Bits.Decl.Implicit; }
|
|
|
|
/// Mark this declaration as implicit.
|
|
void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; }
|
|
|
|
/// Determine whether this declaration is syntactically scoped inside of
|
|
/// a local context, but should behave like a top-level declaration
|
|
/// for name lookup purposes. This is used by lldb.
|
|
bool isHoisted() const { return Bits.Decl.Hoisted; }
|
|
|
|
/// Set whether this declaration should be syntactically scoped inside
|
|
/// of a local context, but should behave like a top-level declaration,
|
|
/// but should behave like a top-level declaration. This is used by lldb.
|
|
void setHoisted(bool hoisted = true) { Bits.Decl.Hoisted = hoisted; }
|
|
|
|
/// Whether this declaration predates the introduction of concurrency.
|
|
bool preconcurrency() const;
|
|
|
|
/// Query whether this declaration was explicitly declared to be safe or
|
|
/// unsafe.
|
|
ExplicitSafety getExplicitSafety() const;
|
|
|
|
private:
|
|
bool isUnsafeComputed() const {
|
|
return Bits.Decl.IsUnsafeComputed;
|
|
}
|
|
|
|
bool isUnsafeRaw() const {
|
|
return Bits.Decl.IsUnsafe;
|
|
}
|
|
|
|
void setUnsafe(bool value) {
|
|
assert(!Bits.Decl.IsUnsafeComputed);
|
|
Bits.Decl.IsUnsafe = value;
|
|
Bits.Decl.IsUnsafeComputed = true;
|
|
}
|
|
|
|
public:
|
|
bool getSemanticAttrsComputed() const {
|
|
return Bits.Decl.SemanticAttrsComputed;
|
|
}
|
|
|
|
void setSemanticAttrsComputed(bool Computed) {
|
|
Bits.Decl.SemanticAttrsComputed = Computed;
|
|
}
|
|
|
|
/// \returns the unparsed comment attached to this declaration.
|
|
RawComment getRawComment() const;
|
|
|
|
std::optional<StringRef> getGroupName() const;
|
|
|
|
std::optional<StringRef> getSourceFileName() const;
|
|
|
|
std::optional<unsigned> getSourceOrder() const;
|
|
|
|
/// Get the declaration that actually provides a doc comment for another.
|
|
const Decl *getDocCommentProvidingDecl() const;
|
|
|
|
/// \returns The brief comment attached to this declaration, or the brief
|
|
/// comment attached to the comment providing decl.
|
|
StringRef getSemanticBriefComment() const;
|
|
|
|
/// Returns true if there is a Clang AST node associated
|
|
/// with self.
|
|
bool hasClangNode() const {
|
|
return Bits.Decl.FromClang;
|
|
}
|
|
|
|
/// Retrieve the Clang AST node from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
ClangNode getClangNode() const {
|
|
if (!Bits.Decl.FromClang)
|
|
return ClangNode();
|
|
|
|
return getClangNodeImpl();
|
|
}
|
|
|
|
/// Retrieve the Clang declaration from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
const clang::Decl *getClangDecl() const {
|
|
if (!Bits.Decl.FromClang)
|
|
return nullptr;
|
|
|
|
return getClangNodeImpl().getAsDecl();
|
|
}
|
|
|
|
/// Retrieve the Clang macro from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
const clang::MacroInfo *getClangMacro() {
|
|
if (!Bits.Decl.FromClang)
|
|
return nullptr;
|
|
|
|
return getClangNodeImpl().getAsMacro();
|
|
}
|
|
|
|
/// If this is the Swift implementation of a declaration imported from ObjC,
|
|
/// returns the imported declaration. (If there are several, only the main
|
|
/// class body will be returned.) Otherwise return \c nullptr.
|
|
///
|
|
/// \seeAlso ExtensionDecl::isObjCInterface()
|
|
Decl *getImplementedObjCDecl() const {
|
|
auto impls = getAllImplementedObjCDecls();
|
|
if (impls.empty())
|
|
return nullptr;
|
|
return impls.front();
|
|
}
|
|
|
|
/// If this is the Swift implementation of a declaration imported from ObjC,
|
|
/// returns the imported declarations. (There may be several for a main class
|
|
/// body; if so, the first will be the class itself.) Otherwise return an empty list.
|
|
///
|
|
/// \seeAlso ExtensionDecl::isObjCInterface()
|
|
llvm::TinyPtrVector<Decl *> getAllImplementedObjCDecls() const;
|
|
|
|
/// If this is the ObjC interface of a declaration implemented in Swift,
|
|
/// returns the implementating declaration. Otherwise return \c nullptr.
|
|
///
|
|
/// \seeAlso ExtensionDecl::isObjCInterface()
|
|
Decl *getObjCImplementationDecl() const;
|
|
|
|
bool getCachedLacksObjCInterfaceOrImplementation() const {
|
|
return Bits.Decl.LacksObjCInterfaceOrImplementation;
|
|
}
|
|
|
|
void setCachedLacksObjCInterfaceOrImplementation(bool value) {
|
|
Bits.Decl.LacksObjCInterfaceOrImplementation = value;
|
|
}
|
|
|
|
/// Return the GenericContext if the Decl has one.
|
|
LLVM_READONLY
|
|
const GenericContext *getAsGenericContext() const;
|
|
|
|
bool hasUnderscoredNaming() const;
|
|
|
|
/// Whether this declaration is from a system module and should be considered
|
|
/// implicitly private.
|
|
bool isPrivateSystemDecl(bool treatNonBuiltinProtocolsAsPublic = true) const;
|
|
|
|
/// Check if this is a declaration defined at the top level of the Swift module
|
|
bool isStdlibDecl() const;
|
|
|
|
/// The effective lifetime resulting from the decorations on the declaration.
|
|
///
|
|
/// Usually, this, not getLifetimeAnnotationFromAttributes should be used.
|
|
LifetimeAnnotation getLifetimeAnnotation() const;
|
|
|
|
/// The source-level lifetime attribute, either @_eagerMove or @_noEagerMove
|
|
/// that the declaration bears.
|
|
///
|
|
/// Usually getLifetimeAnnotation should be used.
|
|
///
|
|
/// Needed to access the attributes before the AST has been fully formed, such
|
|
/// as when printing.
|
|
LifetimeAnnotation getLifetimeAnnotationFromAttributes() const;
|
|
|
|
bool isNoImplicitCopy() const {
|
|
return getAttrs().hasAttribute<NoImplicitCopyAttr>();
|
|
}
|
|
|
|
AvailabilityRange getAvailabilityForLinkage() const;
|
|
|
|
/// Whether this declaration or one of its outer contexts has the
|
|
/// @_weakLinked attribute.
|
|
bool isAlwaysWeakImported() const;
|
|
|
|
/// Whether this declaration is weak-imported from the given module,
|
|
/// either because of the presence of the @_weakLinked attribute, or
|
|
/// because of availability.
|
|
///
|
|
/// Note that \p fromModule should either be the "main module" or
|
|
/// nullptr. (This is because when it is non-null, we query the
|
|
/// current deployment target, and not the deployment target that
|
|
/// the module was built with.)
|
|
///
|
|
/// If \p fromModule is the main module, this returns false when the
|
|
/// declaration is part of the main module, or if the declaration is
|
|
/// at least as available as the current deployment target.
|
|
///
|
|
/// If \p fromModule is null, we instead return true if the
|
|
/// declaration is meant to be weak linked with _some_ deployment
|
|
/// target; that is, the presence of the @_weakLinked attribute or
|
|
/// any kind of availability is enough, irrespective of the current
|
|
/// deployment target.
|
|
bool isWeakImported(ModuleDecl *fromModule) const;
|
|
|
|
/// Returns true if the nature of this declaration allows overrides syntactically.
|
|
///
|
|
/// If this returns true, the decl can be safely casted to ValueDecl.
|
|
bool isSyntacticallyOverridable() const;
|
|
|
|
/// Retrieve the global actor attribute that applies to this declaration,
|
|
/// if any.
|
|
///
|
|
/// This is the "raw" global actor attribute as written directly on the
|
|
/// declaration, along with the nominal type declaration to which it refers,
|
|
/// without any inference rules applied.
|
|
std::optional<std::pair<CustomAttr *, NominalTypeDecl *>>
|
|
getGlobalActorAttr() const;
|
|
|
|
/// Determine whether there is an explicit isolation attribute
|
|
/// of any kind.
|
|
bool hasExplicitIsolationAttribute() const;
|
|
|
|
/// If an alternative module name is specified for this decl, e.g. using
|
|
/// @_originalDefinedIn attribute, this function returns this module name.
|
|
StringRef getAlternateModuleName() const;
|
|
|
|
/// Is this Decl an SPI? It can be directly marked with @_spi or is defined in
|
|
/// an @_spi context.
|
|
bool isSPI() const;
|
|
|
|
/// Returns true if the attribute providing the platform availability
|
|
/// introduction for this decl is an `@_spi_available` attribute.
|
|
bool isAvailableAsSPI() const;
|
|
|
|
/// Determine whether this Decl has either Private or FilePrivate access,
|
|
/// and its DeclContext does not.
|
|
bool isOutermostPrivateOrFilePrivateScope() const;
|
|
|
|
/// Returns an iterable list of the valid `AvailableAttr` and
|
|
/// `AvailabilityDomain` pairs. Unless \p includeInactive is true, attributes
|
|
/// that are considered inactive for the compilation context are filtered out.
|
|
SemanticAvailableAttributes
|
|
getSemanticAvailableAttrs(bool includeInactive = true) const;
|
|
|
|
/// Returns the SemanticAvailableAttr associated with the given
|
|
/// `AvailableAttr` that is attached to this decl. Returns `std::nullopt` if a
|
|
/// valid semantic version of the attribute cannot be constructed (e.g. the
|
|
/// domain cannot be resolved).
|
|
std::optional<SemanticAvailableAttr>
|
|
getSemanticAvailableAttr(const AvailableAttr *attr) const;
|
|
|
|
/// Returns the active platform-specific `@available` attribute for this decl.
|
|
/// There may be multiple `@available` attributes that are relevant to the
|
|
/// current platform, but the returned one has the highest priority.
|
|
std::optional<SemanticAvailableAttr>
|
|
getActiveAvailableAttrForCurrentPlatform() const;
|
|
|
|
/// Returns the active platform-specific `@available` attribute that should be
|
|
/// used to determine the platform introduction version of the decl.
|
|
///
|
|
/// If the declaration does not have a platform introduction attribute of its
|
|
/// own and is a member of an extension then the platform introduction
|
|
/// attribute attached to the extension will be returned instead unless \p
|
|
/// checkExtension is false.
|
|
std::optional<SemanticAvailableAttr>
|
|
getAvailableAttrForPlatformIntroduction(bool checkExtension = true) const;
|
|
|
|
/// Returns true if the declaration is deprecated at the current deployment
|
|
/// target.
|
|
bool isDeprecated() const { return getDeprecatedAttr().has_value(); }
|
|
|
|
/// Returns the first `@available` attribute that indicates that this decl
|
|
/// is deprecated on current deployment target, or `nullptr` otherwise.
|
|
std::optional<SemanticAvailableAttr> getDeprecatedAttr() const;
|
|
|
|
/// Returns the first `@available` attribute that indicates that this decl
|
|
/// will be deprecated in the future, or `nullptr` otherwise.
|
|
std::optional<SemanticAvailableAttr> getSoftDeprecatedAttr() const;
|
|
|
|
/// Returns the first @available attribute that indicates this decl is
|
|
/// unavailable from asynchronous contexts, or `nullptr` otherwise.
|
|
std::optional<SemanticAvailableAttr> getNoAsyncAttr() const;
|
|
|
|
/// Returns true if the decl has been marked unavailable in the Swift language
|
|
/// version that is currently active.
|
|
bool isUnavailableInCurrentSwiftVersion() const;
|
|
|
|
/// Returns true if the decl is always unavailable in the current compilation
|
|
/// context. For example, the decl could be marked explicitly unavailable on
|
|
/// either the current platform or in the current language mode. Returns false
|
|
/// for declarations that are only _potentially_ unavailable because of a
|
|
/// condition that could be satisfied at runtime (like requiring an operating
|
|
/// system version that is higher than the current deployment target).
|
|
///
|
|
/// Note that this query only considers the attributes that are attached
|
|
/// directly to this decl (or the extension it is declared in, if applicable).
|
|
bool isUnavailable() const { return getUnavailableAttr().has_value(); }
|
|
|
|
/// If the decl is always unavailable in the current compilation
|
|
/// context, returns the attribute attached to the decl (or its parent
|
|
/// extension) that makes it unavailable.
|
|
std::optional<SemanticAvailableAttr> getUnavailableAttr() const;
|
|
|
|
/// Returns true if code associated with this declaration should be considerd
|
|
/// unreachable at runtime because the declaration is unavailable in all
|
|
/// execution contexts in which the code may run. This result takes the
|
|
/// availability of parent declarations into account.
|
|
bool isUnreachableAtRuntime() const;
|
|
|
|
/// Returns true if this declaration should be considered available during
|
|
/// SIL/IR lowering. A declaration would not be available during lowering if,
|
|
/// for example, it is annotated as unavailable with `@available` and
|
|
/// optimization settings require that it be omitted. Canonical SIL must not
|
|
/// contain any references to declarations that are unavailable during
|
|
/// lowering because the resulting IR could reference non-existent symbols
|
|
/// and fail to link.
|
|
bool isAvailableDuringLowering() const;
|
|
|
|
/// Returns true if ABI compatibility stubs must be emitted for the given
|
|
/// declaration. Decls marked unavailable with `@available` require these
|
|
/// stubs if the compiler flags have enabled unavailable declaration ABI
|
|
/// compatibility mode.
|
|
bool requiresUnavailableDeclABICompatibilityStubs() const;
|
|
|
|
// List the SPI groups declared with @_spi or inherited by this decl.
|
|
//
|
|
// SPI groups are inherited from the parent contexts only if the local decl
|
|
// doesn't declare any @_spi.
|
|
ArrayRef<Identifier> getSPIGroups() const;
|
|
|
|
/// Returns true if this declaration has any `@backDeployed` attributes.
|
|
bool hasBackDeployedAttr() const;
|
|
|
|
/// Return the declaration upon which the attributes for this declaration
|
|
/// would appear in concrete syntax. This function is necessary because for
|
|
/// semantic analysis, the parser attaches attributes to declarations other
|
|
/// than those on which they, concretely, appear.
|
|
const Decl *getConcreteSyntaxDeclForAttributes() const;
|
|
|
|
/// Return the declaration to which the parser actually attaches attributes in
|
|
/// the abstract syntax tree (see `getConcreteSyntaxDeclForAttributes()`).
|
|
const Decl *getAbstractSyntaxDeclForAttributes() const;
|
|
|
|
/// Apply the specified function to decls that should be placed _next_ to
|
|
/// this decl when constructing AST.
|
|
void forEachDeclToHoist(llvm::function_ref<void(Decl *)> callback) const;
|
|
|
|
/// Emit a diagnostic tied to this declaration.
|
|
template<typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(
|
|
Diag<ArgTypes...> ID,
|
|
typename detail::PassArgument<ArgTypes>::type... Args) const {
|
|
return getDiags().diagnose(this, ID, std::move(Args)...);
|
|
}
|
|
|
|
/// Retrieve the diagnostic engine for diagnostics emission.
|
|
LLVM_READONLY
|
|
DiagnosticEngine &getDiags() const;
|
|
};
|
|
|
|
/// Allocates memory for a Decl with the given \p baseSize. If necessary,
|
|
/// it includes additional space immediately preceding the Decl for a ClangNode.
|
|
/// \note \p baseSize does not need to include space for a ClangNode if
|
|
/// requested -- the necessary space will be added automatically.
|
|
template <typename DeclTy, typename AllocatorTy>
|
|
void *allocateMemoryForDecl(AllocatorTy &allocator, size_t baseSize,
|
|
bool includeSpaceForClangNode) {
|
|
static_assert(alignof(DeclTy) >= sizeof(void *),
|
|
"A pointer must fit in the alignment of the DeclTy!");
|
|
|
|
size_t size = baseSize;
|
|
if (includeSpaceForClangNode)
|
|
size += alignof(DeclTy);
|
|
|
|
void *mem = allocator.Allocate(size, alignof(DeclTy));
|
|
if (includeSpaceForClangNode)
|
|
mem = reinterpret_cast<char *>(mem) + alignof(DeclTy);
|
|
return mem;
|
|
}
|
|
|
|
/// A convenience function object for filtering out decls that are not available
|
|
/// during lowering.
|
|
template <typename T>
|
|
struct AvailableDuringLoweringDeclFilter {
|
|
std::optional<T *> operator()(T *decl) const {
|
|
if (decl->isAvailableDuringLowering())
|
|
return decl;
|
|
return std::nullopt;
|
|
}
|
|
};
|
|
|
|
// A private class for forcing exact field layout.
|
|
class alignas(8) _GenericContext {
|
|
// Not really public. See GenericContext.
|
|
public:
|
|
/// The state of the generic parameters.
|
|
enum class GenericParamsState: uint8_t {
|
|
/// The stored generic parameters represent parsed generic parameters,
|
|
/// written in the source.
|
|
Parsed = 0,
|
|
/// The stored generic parameters represent generic parameters that are
|
|
/// synthesized by the type checker but were not written in the source.
|
|
TypeChecked = 1,
|
|
/// The stored generic parameters represent both the parsed and
|
|
/// type-checked generic parameters.
|
|
ParsedAndTypeChecked = 2,
|
|
};
|
|
|
|
llvm::PointerIntPair<GenericParamList *, 2, GenericParamsState>
|
|
GenericParamsAndState;
|
|
|
|
/// The trailing where clause.
|
|
///
|
|
/// Note that this is not currently serialized, because semantic analysis
|
|
/// moves the trailing where clause into the generic parameter list.
|
|
TrailingWhereClause *TrailingWhere = nullptr;
|
|
|
|
/// The generic signature of this declaration.
|
|
llvm::PointerIntPair<GenericSignature, 1, bool> GenericSigAndBit;
|
|
};
|
|
|
|
class GenericContext : private _GenericContext, public DeclContext {
|
|
friend class GenericParamListRequest;
|
|
friend class GenericSignatureRequest;
|
|
|
|
protected:
|
|
GenericContext(DeclContextKind Kind, DeclContext *Parent,
|
|
GenericParamList *Params);
|
|
|
|
public:
|
|
/// Retrieve the set of parameters to a generic context, or null if
|
|
/// this context is not generic.
|
|
GenericParamList *getGenericParams() const;
|
|
|
|
/// Retrieve the generic parameters as written in source. Unlike
|
|
/// getGenericParams() this will not synthesize generic parameters for
|
|
/// extensions, protocols and certain type aliases.
|
|
GenericParamList *getParsedGenericParams() const;
|
|
|
|
/// Determine whether this context has generic parameters
|
|
/// of its own.
|
|
///
|
|
/// \code
|
|
/// class C<T> {
|
|
/// func f1() {} // isGeneric == false
|
|
/// func f2<T>() {} // isGeneric == true
|
|
/// }
|
|
///
|
|
/// protocol P { // isGeneric == true due to implicit Self param
|
|
/// func p() // isGeneric == false
|
|
/// }
|
|
/// \endcode
|
|
bool isGeneric() const { return getGenericParams() != nullptr; }
|
|
bool hasComputedGenericSignature() const;
|
|
bool isComputingGenericSignature() const;
|
|
|
|
/// Retrieve the trailing where clause for this extension, if any.
|
|
TrailingWhereClause *getTrailingWhereClause() const {
|
|
return TrailingWhere;
|
|
}
|
|
|
|
/// Set the trailing where clause for this extension.
|
|
void setTrailingWhereClause(TrailingWhereClause *trailingWhereClause) {
|
|
TrailingWhere = trailingWhereClause;
|
|
}
|
|
|
|
/// Retrieve the generic signature for this context.
|
|
GenericSignature getGenericSignature() const;
|
|
|
|
/// Retrieve the generic context for this context.
|
|
GenericEnvironment *getGenericEnvironment() const;
|
|
|
|
/// Retrieve the innermost generic parameter types.
|
|
ArrayRef<GenericTypeParamType *> getInnermostGenericParamTypes() const;
|
|
|
|
/// Retrieve the generic requirements.
|
|
ArrayRef<Requirement> getGenericRequirements() const;
|
|
|
|
/// Set the generic signature of this context.
|
|
void setGenericSignature(GenericSignature genericSig);
|
|
|
|
/// Retrieve the position of any where clause for this context's
|
|
/// generic parameters.
|
|
SourceRange getGenericTrailingWhereClauseSourceRange() const;
|
|
|
|
static bool classof(const Decl *D);
|
|
};
|
|
static_assert(sizeof(_GenericContext) + sizeof(DeclContext) ==
|
|
sizeof(GenericContext), "Please add fields to _GenericContext");
|
|
|
|
/// ImportDecl - This represents a single import declaration, e.g.:
|
|
/// import Swift
|
|
/// import typealias Swift.Int
|
|
class ImportDecl final : public Decl,
|
|
private llvm::TrailingObjects<ImportDecl, ImportPath::Element> {
|
|
friend TrailingObjects;
|
|
friend class Decl;
|
|
|
|
SourceLoc ImportLoc;
|
|
SourceLoc KindLoc;
|
|
/// Used to store the real module name corresponding to this import decl in
|
|
/// case module aliasing is used. For example if '-module-alias Foo=Bar' was
|
|
/// passed and this decl is 'import Foo', the real name 'Bar' will be stored.
|
|
Identifier RealModuleName;
|
|
|
|
/// The resolved module.
|
|
ModuleDecl *Mod = nullptr;
|
|
|
|
ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
|
|
SourceLoc KindLoc, ImportPath Path);
|
|
public:
|
|
static ImportDecl *create(ASTContext &C, DeclContext *DC,
|
|
SourceLoc ImportLoc, ImportKind Kind,
|
|
SourceLoc KindLoc,
|
|
ImportPath Path,
|
|
ClangNode ClangN = ClangNode());
|
|
|
|
/// Returns the import kind that is most appropriate for \p VD.
|
|
///
|
|
/// Note that this will never return \c Type; an imported typealias will use
|
|
/// the more specific kind from its underlying type.
|
|
static ImportKind getBestImportKind(const ValueDecl *VD);
|
|
|
|
/// Returns the most appropriate import kind for the given list of decls.
|
|
///
|
|
/// If the list is non-homogeneous, or if there is more than one decl that
|
|
/// cannot be overloaded, returns None.
|
|
static std::optional<ImportKind>
|
|
findBestImportKind(ArrayRef<ValueDecl *> Decls);
|
|
|
|
ImportKind getImportKind() const {
|
|
return static_cast<ImportKind>(Bits.ImportDecl.ImportKind);
|
|
}
|
|
|
|
/// Retrieves the import path as written in the source code.
|
|
///
|
|
/// \returns An \c ImportPath corresponding to this import decl. If module aliasing
|
|
/// was used, this will contain the aliased name of the module; for instance,
|
|
/// if you wrote 'import Foo' but passed '-module-alias Foo=Bar', this import
|
|
/// path will include 'Foo'. This return value is always owned by \c ImportDecl
|
|
/// (which is owned by the AST context), so it can be persisted.
|
|
ImportPath getImportPath() const {
|
|
return ImportPath({ getTrailingObjects<ImportPath::Element>(),
|
|
static_cast<size_t>(Bits.ImportDecl.NumPathElements) });
|
|
}
|
|
|
|
/// Retrieves the import path, replacing any module aliases with real names.
|
|
///
|
|
/// \param scratch An \c ImportPath::Builder which may, if necessary, be used to
|
|
/// construct the return value. It may go unused, so you should not try to
|
|
/// read the result from it; use the return value instead.
|
|
/// \returns An \c ImportPath corresponding to this import decl. If module aliasing
|
|
/// was used, this will contain the real name of the module; for instance,
|
|
/// if you wrote 'import Foo' but passed '-module-alias Foo=Bar', this import
|
|
/// path will include 'Bar'. This return value may be owned by \p scratch,
|
|
/// so it should not be used after \p scratch is destroyed.
|
|
ImportPath getRealImportPath(ImportPath::Builder &scratch) const;
|
|
|
|
/// Retrieves the part of the import path that contains the module name,
|
|
/// as written in the source code.
|
|
///
|
|
/// \returns A \c ImportPath::Module corresponding to this import decl. If module
|
|
/// aliasing was used, this will contain the aliased name of the module; for
|
|
/// instance, if you wrote 'import Foo' but passed '-module-alias Foo=Bar',
|
|
/// this module path will contain 'Foo'. This return value is always owned by
|
|
/// \c ImportDecl (which is owned by the AST context), so it can be persisted.
|
|
ImportPath::Module getModulePath() const {
|
|
return getImportPath().getModulePath(getImportKind());
|
|
}
|
|
|
|
/// Retrieves the part of the import path that contains the module name,
|
|
/// replacing any module aliases with real names.
|
|
///
|
|
/// \param scratch An \c ImportPath::Builder which may, if necessary, be used to
|
|
/// construct the return value. It may go unused, so you should not try to
|
|
/// read the result from it; use the return value instead.
|
|
/// \returns An \c ImportPath::Module corresponding to this import decl. If module
|
|
/// aliasing was used, this will contain the real name of the module; for
|
|
/// instance, if you wrote 'import Foo' but passed '-module-alias Foo=Bar',
|
|
/// the returned path will contain 'Bar'. This return value may be owned
|
|
/// by \p scratch, so it should not be used after \p scratch is destroyed.
|
|
ImportPath::Module getRealModulePath(ImportPath::Builder &scratch) const {
|
|
return getRealImportPath(scratch).getModulePath(getImportKind());
|
|
}
|
|
|
|
ImportPath::Access getAccessPath() const {
|
|
return getImportPath().getAccessPath(getImportKind());
|
|
}
|
|
|
|
bool isExported() const {
|
|
return getAttrs().hasAttribute<ExportedAttr>();
|
|
}
|
|
|
|
bool isTestable() const {
|
|
return getAttrs().hasAttribute<TestableAttr>();
|
|
}
|
|
|
|
ModuleDecl *getModule() const { return Mod; }
|
|
void setModule(ModuleDecl *M) { Mod = M; }
|
|
|
|
/// For a scoped import such as 'import class Foundation.NSString', retrieve
|
|
/// the decls it references. Otherwise, returns an empty array.
|
|
ArrayRef<ValueDecl *> getDecls() const;
|
|
|
|
/// Access level of this import, either explicitly declared or implicit.
|
|
AccessLevel getAccessLevel() const;
|
|
|
|
/// Is the access level of this import implicit, aka a default import?
|
|
bool isAccessLevelImplicit() const;
|
|
|
|
const clang::Module *getClangModule() const {
|
|
return getClangNode().getClangModule();
|
|
}
|
|
|
|
SourceLoc getStartLoc() const { return ImportLoc; }
|
|
SourceLoc getLocFromSource() const {
|
|
return getImportPath().getSourceRange().Start;
|
|
}
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(ImportLoc, getImportPath().getSourceRange().End);
|
|
}
|
|
SourceLoc getKindLoc() const { return KindLoc; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Import;
|
|
}
|
|
};
|
|
|
|
/// An entry in the "inherited" list of a type or extension.
|
|
struct InheritedEntry : public TypeLoc {
|
|
private:
|
|
/// Options on a protocol conformance that are expressed as attributes.
|
|
unsigned RawOptions: 8;
|
|
|
|
/// Whether there was a ~ indicating suppression.
|
|
///
|
|
/// This is true in cases like ~Copyable but not (P & ~Copyable).
|
|
bool IsSuppressed : 1;
|
|
|
|
/// The global actor isolation provided (for a conformance).
|
|
TypeExpr *globalActorIsolationType = nullptr;
|
|
|
|
public:
|
|
InheritedEntry(const TypeLoc &typeLoc);
|
|
|
|
InheritedEntry(const TypeLoc &typeLoc, ProtocolConformanceOptions options,
|
|
bool isSuppressed = false)
|
|
: TypeLoc(typeLoc), RawOptions(options.toRaw()),
|
|
IsSuppressed(isSuppressed),
|
|
globalActorIsolationType(options.getGlobalActorIsolationType()) {}
|
|
|
|
ProtocolConformanceOptions getOptions() const {
|
|
return ProtocolConformanceOptions(RawOptions, globalActorIsolationType);
|
|
}
|
|
|
|
bool isUnchecked() const {
|
|
return getOptions().contains(ProtocolConformanceFlags::Unchecked);
|
|
}
|
|
bool isRetroactive() const {
|
|
return getOptions().contains(ProtocolConformanceFlags::Retroactive);
|
|
}
|
|
bool isPreconcurrency() const {
|
|
return getOptions().contains(ProtocolConformanceFlags::Preconcurrency);
|
|
}
|
|
bool isNonisolated() const {
|
|
return getOptions().contains(ProtocolConformanceFlags::Nonisolated);
|
|
}
|
|
|
|
TypeExpr *getGlobalActorIsolationType() const {
|
|
return globalActorIsolationType;
|
|
}
|
|
|
|
ExplicitSafety getExplicitSafety() const {
|
|
if (getOptions().contains(ProtocolConformanceFlags::Unsafe))
|
|
return ExplicitSafety::Unsafe;
|
|
return ExplicitSafety::Unspecified;
|
|
}
|
|
|
|
bool isSuppressed() const { return IsSuppressed; }
|
|
|
|
void setOption(ProtocolConformanceFlags flag) {
|
|
RawOptions = (getOptions() | flag).toRaw();
|
|
}
|
|
|
|
void setOption(ExplicitSafety safety) {
|
|
RawOptions = (getOptions() - ProtocolConformanceFlags::Unsafe).toRaw();
|
|
switch (safety) {
|
|
case ExplicitSafety::Unspecified:
|
|
case ExplicitSafety::Safe:
|
|
break;
|
|
case ExplicitSafety::Unsafe:
|
|
RawOptions = (getOptions() | ProtocolConformanceFlags::Unsafe).toRaw();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void setSuppressed() {
|
|
assert(!IsSuppressed && "setting suppressed again!?");
|
|
IsSuppressed = true;
|
|
}
|
|
|
|
void dump(raw_ostream &os) const;
|
|
|
|
SWIFT_DEBUG_DUMP;
|
|
};
|
|
|
|
/// A wrapper for the collection of inherited types for either a `TypeDecl` or
|
|
/// an `ExtensionDecl`.
|
|
class InheritedTypes {
|
|
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> Decl;
|
|
ArrayRef<InheritedEntry> Entries;
|
|
|
|
public:
|
|
InheritedTypes(
|
|
llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *> decl);
|
|
InheritedTypes(const class Decl *decl);
|
|
InheritedTypes(const TypeDecl *typeDecl);
|
|
InheritedTypes(const ExtensionDecl *extensionDecl);
|
|
|
|
bool empty() const { return Entries.empty(); }
|
|
size_t size() const { return Entries.size(); }
|
|
IntRange<size_t> const getIndices() { return indices(Entries); }
|
|
|
|
/// Returns the ASTContext associated with the wrapped declaration.
|
|
ASTContext &getASTContext() const;
|
|
|
|
/// Returns the `TypeRepr *` for the entry of the inheritance clause at the
|
|
/// given index.
|
|
TypeRepr *getTypeRepr(unsigned i) const { return Entries[i].getTypeRepr(); }
|
|
|
|
/// Returns the `Type` for the entry of the inheritance clause at the given
|
|
/// index, resolved at the given stage, or `Type()` if resolution fails.
|
|
Type getResolvedType(unsigned i, TypeResolutionStage stage =
|
|
TypeResolutionStage::Interface) const;
|
|
|
|
/// Returns the underlying array of inherited type entries.
|
|
///
|
|
/// NOTE: The `Type` associated with an entry may not be resolved yet.
|
|
ArrayRef<InheritedEntry> getEntries() const { return Entries; }
|
|
|
|
/// Returns the entry of the inheritance clause at the given index.
|
|
///
|
|
/// NOTE: The `Type` associated with the entry may not be resolved yet.
|
|
const InheritedEntry &getEntry(unsigned i) const { return Entries[i]; }
|
|
|
|
// Retrieve the location of the colon character introducing the inheritance
|
|
// clause.
|
|
SourceLoc getColonLoc() const;
|
|
|
|
/// Returns the source location of the beginning of the inheritance clause.
|
|
SourceLoc getStartLoc() const {
|
|
return getEntries().front().getSourceRange().Start;
|
|
}
|
|
|
|
/// Returns the source location of the end of the inheritance clause.
|
|
SourceLoc getEndLoc() const {
|
|
return getEntries().back().getSourceRange().End;
|
|
}
|
|
|
|
/// Compute the SourceRange to be used when removing entry \c i from the
|
|
/// inheritance clause. Accounts for commas and colons as-needed.
|
|
SourceRange getRemovalRange(unsigned i) const;
|
|
};
|
|
|
|
/// ExtensionDecl - This represents a type extension containing methods
|
|
/// associated with the type. This is not a ValueDecl and has no Type because
|
|
/// there are no runtime values of the Extension's type.
|
|
class ExtensionDecl final : public GenericContext, public Decl,
|
|
public IterableDeclContext {
|
|
SourceLoc ExtensionLoc; // Location of 'extension' keyword.
|
|
SourceRange Braces;
|
|
|
|
/// The type being extended.
|
|
TypeRepr *ExtendedTypeRepr;
|
|
|
|
/// The nominal type being extended.
|
|
///
|
|
/// The bit indicates whether binding has been attempted. The pointer can be
|
|
/// null if either no binding was attempted or if binding could not find the
|
|
/// extended nominal.
|
|
llvm::PointerIntPair<NominalTypeDecl *, 1, bool> ExtendedNominal;
|
|
|
|
ArrayRef<InheritedEntry> Inherited;
|
|
|
|
/// The next extension in the linked list of extensions.
|
|
///
|
|
/// The bit indicates whether this extension has been resolved to refer to
|
|
/// a known nominal type.
|
|
llvm::PointerIntPair<ExtensionDecl *, 1, bool> NextExtension
|
|
= {nullptr, false};
|
|
|
|
/// Note that we have added a member into the iterable declaration context.
|
|
void addedMember(Decl *member);
|
|
|
|
friend class ExtensionIterator;
|
|
friend class NominalTypeDecl;
|
|
friend class MemberLookupTable;
|
|
friend class ConformanceLookupTable;
|
|
friend class IterableDeclContext;
|
|
friend class InheritedTypes;
|
|
|
|
ExtensionDecl(SourceLoc extensionLoc, TypeRepr *extendedType,
|
|
ArrayRef<InheritedEntry> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause);
|
|
|
|
/// Retrieve the conformance loader (if any), and removing it in the
|
|
/// same operation. The caller is responsible for loading the
|
|
/// conformances.
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoader() {
|
|
if (!Bits.ExtensionDecl.HasLazyConformances)
|
|
return { nullptr, 0 };
|
|
|
|
return takeConformanceLoaderSlow();
|
|
}
|
|
|
|
/// Slow path for \c takeConformanceLoader().
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoaderSlow();
|
|
|
|
friend class ExtendedNominalRequest;
|
|
friend class Decl;
|
|
public:
|
|
using Decl::getASTContext;
|
|
|
|
/// Create a new extension declaration.
|
|
static ExtensionDecl *create(ASTContext &ctx, SourceLoc extensionLoc,
|
|
TypeRepr *extendedType,
|
|
ArrayRef<InheritedEntry> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause,
|
|
ClangNode clangNode = ClangNode());
|
|
|
|
SourceLoc getStartLoc() const { return ExtensionLoc; }
|
|
SourceLoc getLocFromSource() const { return ExtensionLoc; }
|
|
SourceRange getSourceRange() const {
|
|
if (!Braces.isValid())
|
|
return SourceRange(ExtensionLoc);
|
|
return { ExtensionLoc, Braces.End };
|
|
}
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
bool hasBeenBound() const { return ExtendedNominal.getInt(); }
|
|
|
|
void setExtendedNominal(NominalTypeDecl *n) {
|
|
ExtendedNominal.setPointerAndInt(n, true);
|
|
}
|
|
|
|
/// Retrieve the type being extended.
|
|
///
|
|
/// Only use this entry point when the complete type, as spelled in the source,
|
|
/// is required. For most clients, \c getExtendedNominal(), which provides
|
|
/// only the \c NominalTypeDecl, will suffice.
|
|
Type getExtendedType() const;
|
|
|
|
/// Retrieve the nominal type declaration that is being extended.
|
|
/// Will trip an assertion if the declaration has not already been computed.
|
|
/// In order to fail fast when type checking work is attempted
|
|
/// before extension binding has taken place.
|
|
|
|
NominalTypeDecl *getExtendedNominal() const;
|
|
|
|
/// Compute the nominal type declaration that is being extended.
|
|
NominalTypeDecl *computeExtendedNominal(
|
|
bool excludeMacroExpansions=false) const;
|
|
|
|
/// \c hasBeenBound means nothing if this extension can never been bound
|
|
/// because it is not at the top level.
|
|
bool canNeverBeBound() const;
|
|
|
|
bool hasValidParent() const;
|
|
|
|
/// Retrieve the extended type definition as written in the source, if it exists.
|
|
///
|
|
/// Repr would not be available if the extension was been loaded
|
|
/// from a serialized module.
|
|
TypeRepr *getExtendedTypeRepr() const { return ExtendedTypeRepr; }
|
|
|
|
/// Retrieve the set of protocols that this type inherits (i.e,
|
|
/// explicitly conforms to).
|
|
InheritedTypes getInherited() const { return InheritedTypes(this); }
|
|
|
|
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }
|
|
|
|
bool hasDefaultAccessLevel() const {
|
|
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel != 0;
|
|
}
|
|
|
|
uint8_t getDefaultAndMaxAccessLevelBits() const {
|
|
return Bits.ExtensionDecl.DefaultAndMaxAccessLevel;
|
|
}
|
|
void setDefaultAndMaxAccessLevelBits(AccessLevel defaultAccess,
|
|
AccessLevel maxAccess) {
|
|
Bits.ExtensionDecl.DefaultAndMaxAccessLevel =
|
|
(1 << (static_cast<unsigned>(defaultAccess) - 1)) |
|
|
(1 << (static_cast<unsigned>(maxAccess) - 1));
|
|
}
|
|
|
|
AccessLevel getDefaultAccessLevel() const;
|
|
AccessLevel getMaxAccessLevel() const;
|
|
|
|
void setDefaultAndMaxAccess(AccessLevel defaultAccess,
|
|
AccessLevel maxAccess) {
|
|
assert(!hasDefaultAccessLevel() && "default access level already set");
|
|
assert(maxAccess >= defaultAccess);
|
|
assert(maxAccess != AccessLevel::Private && "private not valid");
|
|
assert(defaultAccess != AccessLevel::Private && "private not valid");
|
|
setDefaultAndMaxAccessLevelBits(defaultAccess, maxAccess);
|
|
assert(getDefaultAccessLevel() == defaultAccess && "not enough bits");
|
|
assert(getMaxAccessLevel() == maxAccess && "not enough bits");
|
|
}
|
|
|
|
void setConformanceLoader(LazyMemberLoader *resolver, uint64_t contextData);
|
|
|
|
/// Determine whether this is a constrained extension, which adds additional
|
|
/// requirements beyond those of the nominal type.
|
|
bool isConstrainedExtension() const;
|
|
|
|
/// Determine whether this extension context is interchangeable with the
|
|
/// original nominal type context.
|
|
///
|
|
/// False if any of the following properties hold:
|
|
/// - the extension is defined in a different module from the original
|
|
/// nominal type decl,
|
|
/// - the extension is constrained, or
|
|
/// - the extension is to a protocol.
|
|
/// FIXME: In a world where protocol extensions are dynamically dispatched,
|
|
/// "extension is to a protocol" would no longer be a reason to use the
|
|
/// extension mangling, because an extension method implementation could be
|
|
/// resiliently moved into the original protocol itself.
|
|
bool isEquivalentToExtendedContext() const;
|
|
|
|
/// Determine whether this extension context is in the same defining module as
|
|
/// the original nominal type context.
|
|
///
|
|
/// \param RespectOriginallyDefinedIn Whether to respect
|
|
/// \c @_originallyDefinedIn attributes or the actual location of the decls.
|
|
bool isInSameDefiningModule(bool RespectOriginallyDefinedIn = true) const;
|
|
|
|
/// Determine whether this extension is equivalent to one that requires at
|
|
/// at least some constraints to be written in the source.
|
|
///
|
|
/// This result will differ from `isConstrainedExtension()` when any of
|
|
/// the generic parameters of the type are invertible, e.g.,
|
|
/// \code
|
|
/// struct X<T: ~Copyable>: ~Copyable { }
|
|
///
|
|
/// // Implies `T: Copyable`. This extension `!isWrittenWithConstraints()`
|
|
/// // and `isConstrainedExtension()`.
|
|
/// extension X { }
|
|
///
|
|
/// // This extension `isWrittenWithConstraints()`
|
|
/// // and `!isConstrainedExtension()`.
|
|
/// extension X where T: ~Copyable { }
|
|
///
|
|
/// // Implies `T: Copyable`. This extension `isWrittenWithConstraints()`
|
|
/// // and `isConstrainedExtension()`.
|
|
/// extension X where T: P { }
|
|
///
|
|
/// // This extension `isWrittenWithConstraints()`
|
|
/// // and `isConstrainedExtension()`.
|
|
/// extension X where T: Q, T: ~Copyable { }
|
|
/// \endcode
|
|
bool isWrittenWithConstraints() const;
|
|
|
|
/// Does this extension add conformance to an invertible protocol for the
|
|
/// extended type?
|
|
///
|
|
/// Returns \c nullopt if the extension does not add conformance to any
|
|
/// invertible protocol. Returns one of the invertible protocols being
|
|
/// conformed to otherwise.
|
|
std::optional<InvertibleProtocolKind>
|
|
isAddingConformanceToInvertible() const;
|
|
|
|
/// If this extension represents an imported Objective-C category, returns the
|
|
/// category's name. Otherwise returns the empty identifier.
|
|
Identifier getObjCCategoryName() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Extension;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
return C->getIterableContextKind()
|
|
== IterableDeclContextKind::ExtensionDecl;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
};
|
|
|
|
/// Iterator that walks the extensions of a particular type.
|
|
class ExtensionIterator {
|
|
ExtensionDecl *current;
|
|
|
|
public:
|
|
ExtensionIterator() : current() { }
|
|
explicit ExtensionIterator(ExtensionDecl *current) : current(current) { }
|
|
|
|
ExtensionDecl *operator*() const { return current; }
|
|
ExtensionDecl *operator->() const { return current; }
|
|
|
|
ExtensionIterator &operator++() {
|
|
current = current->NextExtension.getPointer();
|
|
return *this;
|
|
}
|
|
|
|
ExtensionIterator operator++(int) {
|
|
ExtensionIterator tmp = *this;
|
|
++(*this);
|
|
return tmp;
|
|
}
|
|
|
|
friend bool operator==(ExtensionIterator x, ExtensionIterator y) {
|
|
return x.current == y.current;
|
|
}
|
|
|
|
friend bool operator!=(ExtensionIterator x, ExtensionIterator y) {
|
|
return x.current != y.current;
|
|
}
|
|
};
|
|
|
|
/// Range that covers a set of extensions.
|
|
class ExtensionRange {
|
|
ExtensionIterator first;
|
|
ExtensionIterator last;
|
|
|
|
public:
|
|
|
|
ExtensionRange(ExtensionIterator first, ExtensionIterator last)
|
|
: first(first), last(last) { }
|
|
|
|
typedef ExtensionIterator iterator;
|
|
iterator begin() const { return first; }
|
|
iterator end() const { return last; }
|
|
};
|
|
|
|
|
|
/// This represents one entry in a PatternBindingDecl, which are pairs of
|
|
/// Pattern and Initialization expression. The pattern is always present, but
|
|
/// the initializer can be null if there is none.
|
|
class PatternBindingEntry {
|
|
enum class Flags {
|
|
// 1 << 0 is available
|
|
Removed = 1 << 1,
|
|
/// Whether the contents of this initializer were subsumed by
|
|
/// some other initialization, e.g., a lazy property's initializer
|
|
/// gets subsumed by the getter body.
|
|
Subsumed = 1 << 2,
|
|
};
|
|
llvm::PointerIntPair<Pattern *, 3, OptionSet<Flags>> PatternAndFlags;
|
|
|
|
enum class InitializerStatus {
|
|
/// The init expression has not been typechecked.
|
|
NotChecked = 0,
|
|
/// The init expression has been typechecked but not contextualized.
|
|
Checked,
|
|
/// The init expression has been typechecked and contextualized.
|
|
CheckedAndContextualized,
|
|
};
|
|
|
|
struct InitializerAndEqualLoc {
|
|
// When the initializer is removed we don't actually clear the pointers
|
|
// because we might need to get initializer's source range. Since the
|
|
// initializer is ASTContext-allocated it is safe.
|
|
|
|
/// Exactly the expr the programmer wrote
|
|
Expr *originalInit;
|
|
/// Might be transformed, e.g. for a property wrapper. In the absence of
|
|
/// transformation or synthesis, holds the expr as parsed.
|
|
llvm::PointerIntPair<Expr *, 2, InitializerStatus> initAfterSynthesis;
|
|
/// The location of the equal '=' token.
|
|
SourceLoc EqualLoc;
|
|
};
|
|
|
|
union {
|
|
/// The initializer expression and its '=' token loc.
|
|
InitializerAndEqualLoc InitExpr;
|
|
|
|
/// The text of the initializer expression if deserialized from a module.
|
|
StringRef InitStringRepresentation;
|
|
};
|
|
|
|
enum class PatternFlags {
|
|
IsText = 1 << 0,
|
|
IsFullyValidated = 1 << 1,
|
|
IsFromDebugger = 1 << 2,
|
|
};
|
|
/// The initializer context used for this pattern binding entry.
|
|
llvm::PointerIntPair<PatternBindingInitializer *, 3, OptionSet<PatternFlags>>
|
|
InitContextAndFlags;
|
|
|
|
/// Values captured by this initializer.
|
|
CaptureInfo Captures;
|
|
|
|
friend class Parser;
|
|
friend class PatternBindingInitializer;
|
|
friend class PatternBindingDecl;
|
|
friend class ast_scope::AbstractPatternEntryScope;
|
|
friend class ast_scope::GenericParamScope;
|
|
friend class ast_scope::PatternEntryDeclScope;
|
|
friend class ast_scope::PatternEntryInitializerScope;
|
|
|
|
private:
|
|
// FIXME: This API is transitional. Once the callers of
|
|
// typeCheckPatternBinding are requestified, merge this bit with
|
|
// Flags::Checked.
|
|
friend class PatternBindingEntryRequest;
|
|
friend class PatternBindingCheckedAndContextualizedInitRequest;
|
|
friend class PatternBindingCaptureInfoRequest;
|
|
|
|
bool isFullyValidated() const {
|
|
return InitContextAndFlags.getInt().contains(
|
|
PatternFlags::IsFullyValidated);
|
|
}
|
|
void setFullyValidated() {
|
|
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
|
|
PatternFlags::IsFullyValidated);
|
|
}
|
|
|
|
/// Set if this pattern binding came from the debugger.
|
|
///
|
|
/// Stay away unless you are \c PatternBindingDecl::createForDebugger
|
|
void setFromDebugger() {
|
|
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
|
|
PatternFlags::IsFromDebugger);
|
|
}
|
|
|
|
public:
|
|
/// \p E is the initializer as parsed.
|
|
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
|
|
PatternBindingInitializer *InitContext)
|
|
: PatternAndFlags(P, {}),
|
|
InitExpr({E, {E, InitializerStatus::NotChecked}, EqualLoc}),
|
|
InitContextAndFlags({InitContext, std::nullopt}) {}
|
|
|
|
private:
|
|
Pattern *getPattern() const { return PatternAndFlags.getPointer(); }
|
|
void setPattern(Pattern *P) { PatternAndFlags.setPointer(P); }
|
|
|
|
/// Whether the given pattern binding entry is initialized.
|
|
///
|
|
/// \param onlyExplicit Only consider explicit initializations (rather
|
|
/// than implicitly-generated ones).
|
|
bool isInitialized(bool onlyExplicit = false) const;
|
|
|
|
Expr *getInit() const {
|
|
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
|
|
InitContextAndFlags.getInt().contains(PatternFlags::IsText))
|
|
return nullptr;
|
|
return InitExpr.initAfterSynthesis.getPointer();
|
|
}
|
|
/// Retrieve the initializer if it should be executed to initialize this
|
|
/// particular pattern binding.
|
|
Expr *getExecutableInit() const {
|
|
return isInitializerSubsumed() ? nullptr : getInit();
|
|
}
|
|
SourceRange getOriginalInitRange() const;
|
|
void setInit(Expr *E);
|
|
|
|
/// Gets the text of the initializer expression, stripping out inactive
|
|
/// branches of any #ifs inside the expression.
|
|
StringRef getInitStringRepresentation(SmallVectorImpl<char> &scratch) const;
|
|
|
|
/// Sets the initializer string representation to the string that was
|
|
/// deserialized from a partial module.
|
|
void setInitStringRepresentation(StringRef str) {
|
|
InitStringRepresentation = str;
|
|
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
|
|
PatternFlags::IsText);
|
|
}
|
|
|
|
/// Whether this pattern entry can generate a string representation of its
|
|
/// initializer expression.
|
|
bool hasInitStringRepresentation() const;
|
|
|
|
/// Retrieve the location of the equal '=' token.
|
|
SourceLoc getEqualLoc() const {
|
|
return InitContextAndFlags.getInt().contains(PatternFlags::IsText)
|
|
? SourceLoc()
|
|
: InitExpr.EqualLoc;
|
|
}
|
|
|
|
/// Set the location of the equal '=' token.
|
|
void setEqualLoc(SourceLoc equalLoc) {
|
|
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText) &&
|
|
"cannot set equal loc for textual initializer");
|
|
InitExpr.EqualLoc = equalLoc;
|
|
}
|
|
|
|
/// Retrieve the initializer after the =, if any, as it was written in the
|
|
/// source.
|
|
Expr *getOriginalInit() const;
|
|
|
|
/// Set the initializer after the = as it was written in the source.
|
|
void setOriginalInit(Expr *);
|
|
|
|
InitializerStatus initializerStatus() const {
|
|
if (InitContextAndFlags.getInt().contains(PatternFlags::IsText))
|
|
return InitializerStatus::NotChecked;
|
|
return InitExpr.initAfterSynthesis.getInt();
|
|
}
|
|
bool isInitializerChecked() const {
|
|
return initializerStatus() != InitializerStatus::NotChecked;
|
|
}
|
|
void setInitializerChecked() {
|
|
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText));
|
|
InitExpr.initAfterSynthesis.setInt(InitializerStatus::Checked);
|
|
}
|
|
|
|
bool isInitializerCheckedAndContextualized() const {
|
|
return initializerStatus() == InitializerStatus::CheckedAndContextualized;
|
|
}
|
|
void setInitializerCheckedAndContextualized() {
|
|
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText));
|
|
InitExpr.initAfterSynthesis.setInt(
|
|
InitializerStatus::CheckedAndContextualized);
|
|
}
|
|
|
|
bool isInitializerSubsumed() const {
|
|
return PatternAndFlags.getInt().contains(Flags::Subsumed);
|
|
}
|
|
void setInitializerSubsumed() {
|
|
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Subsumed);
|
|
}
|
|
|
|
/// Returns \c true if the debugger created this pattern binding entry.
|
|
bool isFromDebugger() const {
|
|
return InitContextAndFlags.getInt().contains(PatternFlags::IsFromDebugger);
|
|
}
|
|
|
|
// Return the first variable initialized by this pattern.
|
|
VarDecl *getAnchoringVarDecl() const;
|
|
|
|
// Retrieve the declaration context for the initializer.
|
|
PatternBindingInitializer *getInitContext() const {
|
|
return InitContextAndFlags.getPointer();
|
|
}
|
|
|
|
/// Override the initializer context.
|
|
void setInitContext(PatternBindingInitializer *init) {
|
|
InitContextAndFlags.setPointer(init);
|
|
}
|
|
|
|
SourceLoc getStartLoc() const;
|
|
|
|
/// Retrieve the end location covered by this pattern binding entry.
|
|
///
|
|
/// \param omitAccessors Whether the computation should omit the accessors
|
|
/// from the source range.
|
|
SourceLoc getEndLoc(bool omitAccessors = false) const;
|
|
|
|
/// Retrieve the source range covered by this pattern binding entry.
|
|
///
|
|
/// \param omitAccessors Whether the computation should omit the accessors
|
|
/// from the source range.
|
|
SourceRange getSourceRange(bool omitAccessors = false) const;
|
|
|
|
/// Retrieve the computed capture info, or \c nullopt if it hasn't been
|
|
/// computed yet.
|
|
std::optional<CaptureInfo> getCachedCaptureInfo() const {
|
|
if (!Captures.hasBeenComputed())
|
|
return std::nullopt;
|
|
|
|
return Captures;
|
|
}
|
|
|
|
void setCaptureInfo(CaptureInfo captures) {
|
|
ASSERT(!Captures.hasBeenComputed());
|
|
ASSERT(captures.hasBeenComputed());
|
|
Captures = captures;
|
|
}
|
|
|
|
private:
|
|
SourceLoc getLastAccessorEndLoc() const;
|
|
};
|
|
|
|
/// This decl contains a pattern and optional initializer for a set
|
|
/// of one or more VarDecls declared together.
|
|
///
|
|
/// For example, in
|
|
/// \code
|
|
/// var (a, b) = foo(), (c,d) = bar()
|
|
/// \endcode
|
|
///
|
|
/// this includes two entries in the pattern list. The first contains the
|
|
/// pattern "(a, b)" and the initializer "foo()". The second contains the
|
|
/// pattern "(c, d)" and the initializer "bar()".
|
|
///
|
|
class PatternBindingDecl final : public Decl,
|
|
private llvm::TrailingObjects<PatternBindingDecl, PatternBindingEntry> {
|
|
friend TrailingObjects;
|
|
friend class Decl;
|
|
friend class PatternBindingEntryRequest;
|
|
friend class PatternBindingCheckedAndContextualizedInitRequest;
|
|
friend class PatternBindingCaptureInfoRequest;
|
|
|
|
SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present.
|
|
SourceLoc VarLoc; ///< Location of the 'var' keyword.
|
|
|
|
friend class Decl;
|
|
|
|
PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc, unsigned NumPatternEntries,
|
|
DeclContext *Parent);
|
|
SourceLoc getLocFromSource() const { return VarLoc; }
|
|
public:
|
|
static PatternBindingDecl *create(ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
ArrayRef<PatternBindingEntry> PatternList,
|
|
DeclContext *Parent);
|
|
|
|
static PatternBindingDecl *create(ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc, Pattern *Pat,
|
|
SourceLoc EqualLoc, Expr *E,
|
|
DeclContext *Parent);
|
|
|
|
static PatternBindingDecl *createImplicit(ASTContext &Ctx,
|
|
StaticSpellingKind StaticSpelling,
|
|
Pattern *Pat, Expr *E,
|
|
DeclContext *Parent,
|
|
SourceLoc VarLoc = SourceLoc());
|
|
|
|
static PatternBindingDecl *createDeserialized(
|
|
ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
unsigned NumPatternEntries,
|
|
DeclContext *Parent);
|
|
|
|
// A dedicated entrypoint that allows LLDB to create pattern bindings
|
|
// that look implicit to the compiler but contain user code.
|
|
static PatternBindingDecl *createForDebugger(ASTContext &Ctx,
|
|
StaticSpellingKind Spelling,
|
|
Pattern *Pat, Expr *E,
|
|
DeclContext *Parent);
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() ? StaticLoc : VarLoc;
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
unsigned getNumPatternEntries() const {
|
|
return Bits.PatternBindingDecl.NumPatternEntries;
|
|
}
|
|
|
|
ArrayRef<PatternBindingEntry> getPatternList() const {
|
|
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
|
|
}
|
|
|
|
/// Returns the typechecked binding entry at the given index.
|
|
const PatternBindingEntry *getCheckedPatternBindingEntry(unsigned i) const;
|
|
|
|
/// Clean up walking the initializers for the pattern
|
|
class InitIterator {
|
|
|
|
const PatternBindingDecl &decl;
|
|
unsigned currentPatternEntryIndex;
|
|
|
|
void next() { ++currentPatternEntryIndex; }
|
|
|
|
public:
|
|
using value_type = Expr *;
|
|
using pointer = value_type;
|
|
using reference = value_type;
|
|
using difference_type = unsigned;
|
|
|
|
InitIterator(const PatternBindingDecl &decl, unsigned start = 0)
|
|
: decl(decl), currentPatternEntryIndex(start) {}
|
|
|
|
InitIterator &operator++() {
|
|
next();
|
|
return *this;
|
|
}
|
|
|
|
InitIterator operator++(int) {
|
|
InitIterator newIterator(decl, currentPatternEntryIndex);
|
|
newIterator.next();
|
|
return newIterator;
|
|
}
|
|
|
|
pointer operator->() { return decl.getInit(currentPatternEntryIndex); }
|
|
|
|
pointer operator*() { return decl.getInit(currentPatternEntryIndex); }
|
|
|
|
difference_type operator-(const InitIterator &other) {
|
|
return currentPatternEntryIndex - other.currentPatternEntryIndex;
|
|
}
|
|
|
|
bool operator==(const InitIterator &other) const {
|
|
return &decl == &other.decl &&
|
|
currentPatternEntryIndex == other.currentPatternEntryIndex;
|
|
}
|
|
|
|
bool operator!=(const InitIterator &other) const {
|
|
return !(*this == other);
|
|
}
|
|
};
|
|
|
|
InitIterator beginInits() const { return InitIterator(*this); }
|
|
|
|
InitIterator endInits() const {
|
|
return InitIterator(*this, getNumPatternEntries());
|
|
}
|
|
|
|
llvm::iterator_range<InitIterator> initializers() const {
|
|
return llvm::make_range(beginInits(), endInits());
|
|
}
|
|
|
|
void setInitStringRepresentation(unsigned i, StringRef str) {
|
|
getMutablePatternList()[i].setInitStringRepresentation(str);
|
|
}
|
|
|
|
/// Whether the given pattern entry is initialized.
|
|
bool isInitialized(unsigned i) const {
|
|
return getPatternList()[i].isInitialized();
|
|
}
|
|
|
|
Expr *getInit(unsigned i) const {
|
|
return getPatternList()[i].getInit();
|
|
}
|
|
Expr *getExecutableInit(unsigned i) const {
|
|
return getPatternList()[i].getExecutableInit();
|
|
}
|
|
Expr *getOriginalInit(unsigned i) const {
|
|
return getPatternList()[i].getOriginalInit();
|
|
}
|
|
|
|
SourceRange getOriginalInitRange(unsigned i) const {
|
|
return getPatternList()[i].getOriginalInitRange();
|
|
}
|
|
|
|
void setInit(unsigned i, Expr *E) {
|
|
getMutablePatternList()[i].setInit(E);
|
|
}
|
|
|
|
void setOriginalInit(unsigned i, Expr *E) {
|
|
getMutablePatternList()[i].setOriginalInit(E);
|
|
}
|
|
|
|
/// Returns a typechecked init expression for the pattern at the given
|
|
/// index.
|
|
Expr *getContextualizedInit(unsigned i) const;
|
|
|
|
/// Returns an init expression for the pattern at the given index.
|
|
/// The initializer is fully type checked, including effects checking.
|
|
Expr *getCheckedAndContextualizedInit(unsigned i) const;
|
|
|
|
/// Returns the result of `getCheckedAndContextualizedInit()` if the init is
|
|
/// not subsumed. Otherwise, returns `nullptr`.
|
|
Expr *getCheckedAndContextualizedExecutableInit(unsigned i) const;
|
|
|
|
Pattern *getPattern(unsigned i) const {
|
|
return getPatternList()[i].getPattern();
|
|
}
|
|
|
|
void setPattern(unsigned i, Pattern *P, bool isFullyValidated = false);
|
|
|
|
bool isFullyValidated(unsigned i) const {
|
|
return getPatternList()[i].isFullyValidated();
|
|
}
|
|
|
|
PatternBindingInitializer *getInitContext(unsigned i) const {
|
|
return getPatternList()[i].getInitContext();
|
|
}
|
|
|
|
void setInitContext(unsigned i, PatternBindingInitializer *init) {
|
|
if (init) {
|
|
init->setBinding(this, i);
|
|
}
|
|
getMutablePatternList()[i].setInitContext(init);
|
|
}
|
|
|
|
/// Retrieve the capture info for the initializer at the given index,
|
|
/// computing if needed.
|
|
CaptureInfo getCaptureInfo(unsigned i) const;
|
|
|
|
/// Given that this PBD is the parent pattern for the specified VarDecl,
|
|
/// return the entry of the VarDecl in our PatternList. For example, in:
|
|
///
|
|
/// let (a,b) = foo(), (c,d) = bar()
|
|
///
|
|
/// "a" and "b" will have index 0, since they correspond to the first pattern,
|
|
/// and "c" and "d" will have index 1 since they correspond to the second one.
|
|
unsigned getPatternEntryIndexForVarDecl(const VarDecl *VD) const;
|
|
|
|
bool isInitializerChecked(unsigned i) const {
|
|
return getPatternList()[i].isInitializerChecked();
|
|
}
|
|
|
|
void setInitializerChecked(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerChecked();
|
|
}
|
|
|
|
bool isInitializerSubsumed(unsigned i) const {
|
|
return getPatternList()[i].isInitializerSubsumed();
|
|
}
|
|
|
|
void setInitializerSubsumed(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerSubsumed();
|
|
}
|
|
|
|
ActorIsolation getInitializerIsolation(unsigned i) const;
|
|
|
|
/// Does this binding declare something that requires storage?
|
|
bool hasStorage() const;
|
|
|
|
/// Determines whether this binding either has an initializer expression, or is
|
|
/// default initialized, without performing any type checking on it.
|
|
bool isDefaultInitializable() const {
|
|
for (unsigned i : range(getNumPatternEntries()))
|
|
if (!isDefaultInitializable(i))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Can the pattern at index i be default initialized?
|
|
bool isDefaultInitializable(unsigned i) const;
|
|
|
|
/// Can the property wrapper be used to provide default initialization?
|
|
bool isDefaultInitializableViaPropertyWrapper(unsigned i) const;
|
|
|
|
/// Does this pattern have a user-provided initializer expression?
|
|
bool isExplicitlyInitialized(unsigned i) const;
|
|
|
|
/// Whether the pattern entry at the given index can generate a string
|
|
/// representation of its initializer expression.
|
|
bool hasInitStringRepresentation(unsigned i) const {
|
|
return getPatternList()[i].hasInitStringRepresentation();
|
|
}
|
|
|
|
SourceLoc getEqualLoc(unsigned i) const;
|
|
|
|
/// When the pattern binding contains only a single variable with no
|
|
/// destructuring, retrieve that variable.
|
|
VarDecl *getSingleVar() const;
|
|
|
|
/// Return the first variable initialized by the pattern at the given index.
|
|
VarDecl *getAnchoringVarDecl(unsigned i) const;
|
|
|
|
bool isStatic() const { return Bits.PatternBindingDecl.IsStatic; }
|
|
void setStatic(bool s) { Bits.PatternBindingDecl.IsStatic = s; }
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(
|
|
Bits.PatternBindingDecl.StaticSpelling);
|
|
}
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
|
|
/// Is the pattern binding entry for this variable currently being computed?
|
|
bool isComputingPatternBindingEntry(const VarDecl *vd) const;
|
|
|
|
/// Is this an "async let" declaration?
|
|
bool isAsyncLet() const;
|
|
|
|
/// Gets the text of the initializer expression for the pattern entry at the
|
|
/// given index, stripping out inactive branches of any #ifs inside the
|
|
/// expression.
|
|
StringRef getInitStringRepresentation(unsigned i,
|
|
SmallVectorImpl<char> &scratch) const {
|
|
return getPatternList()[i].getInitStringRepresentation(scratch);
|
|
}
|
|
|
|
/// Returns \c true if this pattern binding was created by the debugger.
|
|
bool isDebuggerBinding() const { return Bits.PatternBindingDecl.IsDebugger; }
|
|
|
|
/// Returns the \c VarDecl in this PBD at the same offset in the same
|
|
/// pattern entry as \p otherVar is in its PBD, or \c nullptr if this PBD is
|
|
/// too different from \p otherVar 's to find an equivalent variable.
|
|
VarDecl *getVarAtSimilarStructuralPosition(VarDecl *otherVar);
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PatternBinding;
|
|
}
|
|
|
|
private:
|
|
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
|
|
// Pattern entries are tail allocated.
|
|
return {getTrailingObjects<PatternBindingEntry>(), getNumPatternEntries()};
|
|
}
|
|
};
|
|
|
|
/// TopLevelCodeDecl - This decl is used as a container for top-level
|
|
/// expressions and statements in the main module. It is always a direct
|
|
/// child of a SourceFile. The primary reason for building these is to give
|
|
/// top-level statements a DeclContext which is distinct from the file itself.
|
|
/// This, among other things, makes it easier to distinguish between local
|
|
/// top-level variables (which are not live past the end of the statement) and
|
|
/// global variables.
|
|
class TopLevelCodeDecl : public DeclContext, public Decl {
|
|
BraceStmt *Body;
|
|
SourceLoc getLocFromSource() const { return getStartLoc(); }
|
|
friend class Decl;
|
|
public:
|
|
TopLevelCodeDecl(DeclContext *Parent, BraceStmt *Body = nullptr)
|
|
: DeclContext(DeclContextKind::TopLevelCodeDecl, Parent),
|
|
Decl(DeclKind::TopLevelCode, Parent),
|
|
Body(Body) {}
|
|
|
|
BraceStmt *getBody() const { return Body; }
|
|
void setBody(BraceStmt *b) { Body = b; }
|
|
|
|
SourceLoc getStartLoc() const;
|
|
SourceRange getSourceRange() const;
|
|
|
|
LLVM_READONLY
|
|
ASTContext &getASTContext() const { return DeclContext::getASTContext(); }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::TopLevelCode;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
};
|
|
|
|
/// SerializedTopLevelCodeDeclContext - This represents what was originally a
|
|
/// TopLevelCodeDecl during serialization. It is preserved only to maintain the
|
|
/// correct AST structure and remangling after deserialization.
|
|
class SerializedTopLevelCodeDeclContext : public DeclContext {
|
|
public:
|
|
SerializedTopLevelCodeDeclContext(DeclContext *Parent)
|
|
: DeclContext(DeclContextKind::SerializedTopLevelCodeDecl, Parent) {}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
return DC->getContextKind() == DeclContextKind::SerializedTopLevelCodeDecl;
|
|
}
|
|
};
|
|
|
|
class OpaqueTypeDecl;
|
|
|
|
/// ValueDecl - All named decls that are values in the language. These can
|
|
/// have a type, etc.
|
|
class ValueDecl : public Decl {
|
|
public:
|
|
enum : unsigned { InvalidDiscriminator = 0xFFFF };
|
|
|
|
private:
|
|
DeclName Name;
|
|
SourceLoc NameLoc;
|
|
llvm::PointerIntPair<Type, 3, OptionalEnum<AccessLevel>> TypeAndAccess;
|
|
unsigned LocalDiscriminator = InvalidDiscriminator;
|
|
|
|
struct {
|
|
/// Whether the "IsObjC" bit has been computed yet.
|
|
unsigned isObjCComputed : 1;
|
|
|
|
/// Whether this declaration is exposed to Objective-C.
|
|
unsigned isObjC : 1;
|
|
|
|
/// Whether the "overridden" declarations have been computed already.
|
|
unsigned hasOverriddenComputed : 1;
|
|
|
|
/// Whether there are any "overridden" declarations. The actual overridden
|
|
/// declarations are kept in a side table in the ASTContext.
|
|
unsigned hasOverridden : 1;
|
|
|
|
/// Whether the "isDynamic" bit has been computed yet.
|
|
unsigned isDynamicComputed : 1;
|
|
|
|
/// Whether this declaration is 'dynamic', meaning that all uses of
|
|
/// the declaration will go through an extra level of indirection that
|
|
/// allows the entity to be replaced at runtime.
|
|
unsigned isDynamic : 1;
|
|
|
|
/// Whether the DynamicallyReplacedDeclRequest request was evaluated and
|
|
/// output a null pointer.
|
|
unsigned noDynamicallyReplacedDecl : 1;
|
|
|
|
/// Whether the OpaqueResultTypeRequest request was evaluated and produced
|
|
/// a null pointer.
|
|
unsigned noOpaqueResultType : 1;
|
|
|
|
/// Whether the "isFinal" bit has been computed yet.
|
|
unsigned isFinalComputed : 1;
|
|
|
|
/// Whether this declaration is 'final'. A final class can't be subclassed,
|
|
/// a final class member can't be overridden.
|
|
unsigned isFinal : 1;
|
|
|
|
/// Whether the "isIUO" bit" has been computed yet.
|
|
unsigned isIUOComputed : 1;
|
|
|
|
/// Whether this declaration produces an implicitly unwrapped
|
|
/// optional result.
|
|
unsigned isIUO : 1;
|
|
|
|
/// Whether we've evaluated the ApplyAccessNoteRequest.
|
|
unsigned accessNoteApplied : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
friend class DynamicallyReplacedDeclRequest;
|
|
friend class OverriddenDeclsRequest;
|
|
friend class IsObjCRequest;
|
|
friend class IsFinalRequest;
|
|
friend class IsDynamicRequest;
|
|
friend class IsImplicitlyUnwrappedOptionalRequest;
|
|
friend class InterfaceTypeRequest;
|
|
friend class CheckRedeclarationRequest;
|
|
friend class ActorIsolationRequest;
|
|
friend class OpaqueResultTypeRequest;
|
|
friend class ApplyAccessNoteRequest;
|
|
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
protected:
|
|
ValueDecl(DeclKind K,
|
|
llvm::PointerUnion<DeclContext *, ASTContext *> context,
|
|
DeclName name, SourceLoc NameLoc)
|
|
: Decl(K, context), Name(name), NameLoc(NameLoc) {
|
|
Bits.ValueDecl.AlreadyInLookupTable = false;
|
|
Bits.ValueDecl.CheckedRedeclaration = false;
|
|
Bits.ValueDecl.IsUserAccessible = true;
|
|
Bits.ValueDecl.Synthesized = false;
|
|
}
|
|
|
|
// MemberLookupTable borrows a bit from this type
|
|
friend class MemberLookupTable;
|
|
bool isAlreadyInLookupTable() {
|
|
return Bits.ValueDecl.AlreadyInLookupTable;
|
|
}
|
|
void setAlreadyInLookupTable(bool value = true) {
|
|
Bits.ValueDecl.AlreadyInLookupTable = value;
|
|
}
|
|
|
|
/// Determine whether we have already checked whether this
|
|
/// declaration is a redeclaration.
|
|
bool alreadyCheckedRedeclaration() const {
|
|
return Bits.ValueDecl.CheckedRedeclaration;
|
|
}
|
|
|
|
/// Set whether we have already checked this declaration as a
|
|
/// redeclaration.
|
|
void setCheckedRedeclaration() {
|
|
Bits.ValueDecl.CheckedRedeclaration = true;
|
|
}
|
|
|
|
public:
|
|
/// Find the import that makes the given declaration available.
|
|
std::optional<AttributedImport<ImportedModule>>
|
|
findImport(const DeclContext *fromDC) const;
|
|
|
|
/// Return true if this protocol member is a protocol requirement.
|
|
///
|
|
/// Asserts if this is not a member of a protocol.
|
|
bool isProtocolRequirement() const;
|
|
|
|
/// Return true if this is a member implementation for an \c @_objcImplementation
|
|
/// extension.
|
|
bool isObjCMemberImplementation() const;
|
|
|
|
void setUserAccessible(bool Accessible) {
|
|
Bits.ValueDecl.IsUserAccessible = Accessible;
|
|
}
|
|
|
|
bool isUserAccessible() const {
|
|
return Bits.ValueDecl.IsUserAccessible;
|
|
}
|
|
|
|
/// Whether this decl has been synthesized by the compiler for use by the
|
|
/// user.
|
|
///
|
|
/// This is a refinement of isImplicit; all synthesized decls are implicit,
|
|
/// but not all implicit decls are synthesized. The difference comes down to
|
|
/// whether or not the decl is user-facing, e.g the implicit memberwise
|
|
/// initializer is considered synthesized. Decls that are only meant for the
|
|
/// compiler, e.g the implicit FuncDecl for a DeferStmt, are not considered
|
|
/// synthesized.
|
|
bool isSynthesized() const {
|
|
return Bits.ValueDecl.Synthesized;
|
|
}
|
|
|
|
void setSynthesized(bool value = true) {
|
|
Bits.ValueDecl.Synthesized = value;
|
|
}
|
|
|
|
/// Does this have a 'distributed' modifier?
|
|
///
|
|
/// Only member methods and computed properties of a `distributed actor`
|
|
/// can be distributed.
|
|
bool isDistributed() const;
|
|
|
|
/// Is this a '_distributed_get' accessor?
|
|
///
|
|
/// These are special accessors used by distributed thunks, implementing
|
|
/// `distributed var get { }` accessors.
|
|
bool isDistributedGetAccessor() const;
|
|
|
|
bool hasName() const { return bool(Name); }
|
|
bool isOperator() const { return Name.isOperator(); }
|
|
|
|
/// Retrieve the full name of the declaration.
|
|
DeclName getName() const { return Name; }
|
|
void setName(DeclName name) { Name = name; }
|
|
|
|
/// Retrieve the base name of the declaration, ignoring any argument
|
|
/// names.
|
|
DeclBaseName getBaseName() const { return Name.getBaseName(); }
|
|
|
|
Identifier getBaseIdentifier() const {
|
|
return Name.getBaseIdentifier();
|
|
}
|
|
|
|
/// Generates a DeclNameRef referring to this declaration with as much
|
|
/// specificity as possible.
|
|
DeclNameRef createNameRef() const {
|
|
return DeclNameRef(Name);
|
|
}
|
|
|
|
/// Retrieve the C declaration name that names this function, or empty
|
|
/// string if it has none.
|
|
StringRef getCDeclName() const;
|
|
|
|
/// Retrieve the name to use for this declaration when interoperating
|
|
/// with the Objective-C runtime.
|
|
///
|
|
/// \returns A "selector" containing the runtime name. For non-method
|
|
/// entities (classes, protocols, properties), this operation will
|
|
/// return a zero-parameter selector with the appropriate name in its
|
|
/// first slot.
|
|
std::optional<ObjCSelector>
|
|
getObjCRuntimeName(bool skipIsObjCResolution = false) const;
|
|
|
|
/// Determine whether the given declaration can infer @objc, or the
|
|
/// Objective-C name, if used to satisfy the given requirement.
|
|
bool canInferObjCFromRequirement(ValueDecl *requirement);
|
|
|
|
SourceLoc getNameLoc() const { return NameLoc; }
|
|
|
|
/// Returns \c true if this value decl is inlinable with attributes
|
|
/// \c \@usableFromInline, \c \@inlinalbe, and \c \@_alwaysEmitIntoClient
|
|
bool isUsableFromInline() const;
|
|
|
|
/// Returns \c true if this declaration is *not* intended to be used directly
|
|
/// by application developers despite the visibility.
|
|
bool shouldHideFromEditor() const;
|
|
|
|
bool hasAccess() const {
|
|
return TypeAndAccess.getInt().hasValue();
|
|
}
|
|
|
|
/// Access control is done by Requests.
|
|
friend class AccessLevelRequest;
|
|
|
|
/// Returns the access level specified explicitly by the user, or provided by
|
|
/// default according to language rules.
|
|
///
|
|
/// Most of the time this is not the interesting value to check; access is
|
|
/// limited by enclosing scopes per SE-0025. Use #getFormalAccessScope to
|
|
/// check if access control is being used consistently, and to take features
|
|
/// such as \c \@testable and \c \@usableFromInline into account.
|
|
///
|
|
/// \sa getFormalAccessScope
|
|
/// \sa hasOpenAccess
|
|
AccessLevel getFormalAccess() const;
|
|
|
|
/// Returns the outermost DeclContext from which this declaration can be
|
|
/// accessed, or null if the declaration is public.
|
|
///
|
|
/// This is used when calculating if access control is being used
|
|
/// consistently. If \p useDC is provided (the location where the value is
|
|
/// being used), features that affect formal access such as \c \@testable are
|
|
/// taken into account.
|
|
///
|
|
/// \invariant
|
|
/// <code>value.isAccessibleFrom(
|
|
/// value.getFormalAccessScope().getDeclContext())</code>
|
|
///
|
|
/// If \p treatUsableFromInlineAsPublic is true, declarations marked with the
|
|
/// \c \@usableFromInline attribute are treated as public. This is normally
|
|
/// false for name lookup and other source language concerns, but true when
|
|
/// computing the linkage of generated functions.
|
|
///
|
|
/// \sa getFormalAccess
|
|
/// \sa isAccessibleFrom
|
|
/// \sa hasOpenAccess
|
|
AccessScope
|
|
getFormalAccessScope(const DeclContext *useDC = nullptr,
|
|
bool treatUsableFromInlineAsPublic = false) const;
|
|
|
|
|
|
/// Copy the formal access level and @usableFromInline attribute from
|
|
/// \p source.
|
|
///
|
|
/// If \p sourceIsParentContext is true, an access level of \c private will
|
|
/// be copied as \c fileprivate, to ensure that this declaration will be
|
|
/// available everywhere \p source is.
|
|
void copyFormalAccessFrom(const ValueDecl *source,
|
|
bool sourceIsParentContext = false);
|
|
|
|
/// Returns the access level that actually controls how a declaration should
|
|
/// be emitted and may be used.
|
|
///
|
|
/// This is the access used when making optimization and code generation
|
|
/// decisions. It should not be used at the AST or semantic level.
|
|
AccessLevel getEffectiveAccess() const;
|
|
|
|
void setAccess(AccessLevel access) {
|
|
assert(!hasAccess() && "access already set");
|
|
overwriteAccess(access);
|
|
}
|
|
|
|
/// Overwrite the access of this declaration.
|
|
///
|
|
/// This is needed in the LLDB REPL.
|
|
void overwriteAccess(AccessLevel access) {
|
|
TypeAndAccess.setInt(access);
|
|
}
|
|
|
|
/// Returns true if this declaration is accessible from the given context.
|
|
///
|
|
/// A private declaration is accessible from any DeclContext within the same
|
|
/// source file.
|
|
///
|
|
/// An internal declaration is accessible from any DeclContext within the same
|
|
/// module.
|
|
///
|
|
/// A public declaration is accessible everywhere.
|
|
///
|
|
/// If \p DC is null, returns true only if this declaration is public.
|
|
///
|
|
/// If \p forConformance is true, we ignore the visibility of the protocol
|
|
/// when evaluating protocol extension members. This language rule allows a
|
|
/// protocol extension of a private protocol to provide default
|
|
/// implementations for the requirements of a public protocol, even when
|
|
/// the default implementations are not visible to name lookup.
|
|
bool isAccessibleFrom(const DeclContext *DC,
|
|
bool forConformance = false,
|
|
bool allowUsableFromInline = false) const;
|
|
|
|
|
|
/// Returns whether this declaration should be treated as \c open from
|
|
/// \p useDC. This is very similar to #getFormalAccess, but takes
|
|
/// \c \@testable into account.
|
|
///
|
|
/// This is mostly only useful when considering requirements on an override:
|
|
/// if the base declaration is \c open, the override might have to be too.
|
|
bool hasOpenAccess(const DeclContext *useDC) const;
|
|
|
|
/// True if opted in to bypass a resilience check at the use site in the
|
|
/// \p accessingModule that references decls defined in a module
|
|
/// that allows non-resilient access within the same package.
|
|
bool bypassResilienceInPackage(ModuleDecl *accessingModule) const;
|
|
|
|
/// FIXME: This is deprecated.
|
|
bool isRecursiveValidation() const;
|
|
|
|
/// Retrieve the "interface" type of this value, which uses
|
|
/// GenericTypeParamType if the declaration is generic. For a generic
|
|
/// function, this will have a GenericFunctionType with a
|
|
/// GenericSignature inside the type.
|
|
Type getInterfaceType() const;
|
|
bool hasInterfaceType() const;
|
|
|
|
/// Set the interface type for the given value.
|
|
void setInterfaceType(Type type);
|
|
|
|
/// isInstanceMember - Determine whether this value is an instance member
|
|
/// of an enum or protocol.
|
|
bool isInstanceMember() const;
|
|
|
|
/// Retrieve the context discriminator for this local value, which
|
|
/// is the index of this declaration in the sequence of
|
|
/// discriminated declarations with the same name in the current
|
|
/// context. Only local functions and variables with getters and
|
|
/// setters have discriminators.
|
|
unsigned getLocalDiscriminator() const;
|
|
void setLocalDiscriminator(unsigned index);
|
|
|
|
/// Whether this declaration has a local discriminator.
|
|
bool hasLocalDiscriminator() const;
|
|
|
|
/// Return the "raw" local discriminator, without computing it.
|
|
unsigned getRawLocalDiscriminator() const { return LocalDiscriminator; }
|
|
|
|
/// Retrieve the declaration that this declaration overrides, if any.
|
|
ValueDecl *getOverriddenDecl() const;
|
|
|
|
/// Retrieve the declaration that this declaration overrides, including super
|
|
/// deinit.
|
|
ValueDecl *getOverriddenDeclOrSuperDeinit() const;
|
|
|
|
/// Retrieve the declarations that this declaration overrides, if any.
|
|
llvm::TinyPtrVector<ValueDecl *> getOverriddenDecls() const;
|
|
|
|
/// Set the declaration that this declaration overrides.
|
|
void setOverriddenDecl(ValueDecl *overridden) {
|
|
setOverriddenDecls(overridden);
|
|
}
|
|
|
|
/// Set the declarations that this declaration overrides.
|
|
void setOverriddenDecls(ArrayRef<ValueDecl *> overridden);
|
|
|
|
/// Whether the overridden declarations have already been computed.
|
|
bool overriddenDeclsComputed() const;
|
|
|
|
/// Compute the untyped overload signature for this declaration.
|
|
OverloadSignature getOverloadSignature() const;
|
|
|
|
/// Retrieve the type used to describe this entity for the purposes of
|
|
/// overload resolution.
|
|
CanType getOverloadSignatureType() const;
|
|
|
|
/// Returns true if the decl requires Objective-C interop.
|
|
///
|
|
/// This can be true even if there is no 'objc' attribute on the declaration.
|
|
/// In that case it was inferred by the type checker and set with a call to
|
|
/// markAsObjC().
|
|
bool isObjC() const;
|
|
|
|
/// Note whether this declaration is known to be exposed to Objective-C.
|
|
void setIsObjC(bool Value);
|
|
|
|
/// Is this declaration semantically 'final', meaning that the type checker
|
|
/// should treat it as final even if the ABI does not?
|
|
bool isSemanticallyFinal() const;
|
|
|
|
/// Is this declaration 'final'?
|
|
bool isFinal() const;
|
|
|
|
/// Is this declaration marked with 'dynamic'?
|
|
bool isDynamic() const;
|
|
|
|
/// Returns whether accesses to this declaration are asynchronous.
|
|
/// If the declaration is neither `AbstractFunctionDecl` nor
|
|
/// `AbstractStorageDecl`, returns `false`.
|
|
bool isAsync() const;
|
|
|
|
/// Returns whether this function represents a defer body.
|
|
bool isDeferBody() const;
|
|
|
|
private:
|
|
bool isObjCDynamic() const {
|
|
return isObjC() && isDynamic();
|
|
}
|
|
|
|
bool isNativeDynamic() const {
|
|
return !isObjC() && isDynamic();
|
|
}
|
|
|
|
bool isObjCDynamicInGenericClass() const;
|
|
|
|
public:
|
|
/// Should we use Objective-C method dispatch for this decl.
|
|
bool shouldUseObjCDispatch() const {
|
|
return isObjCDynamic();
|
|
}
|
|
|
|
/// Should we use native dynamic function replacement dispatch for this decl.
|
|
bool shouldUseNativeDynamicDispatch() const {
|
|
return isNativeDynamic();
|
|
}
|
|
|
|
/// Should we use Objective-C category based function replacement for this
|
|
/// decl.
|
|
/// This is all `@objc dynamic` methods except for such methods in native
|
|
/// generic classes. We can't use a category for generic classes so we use
|
|
/// native replacement instead (this behavior is only enabled with
|
|
/// -enable-implicit-dynamic).
|
|
bool shouldUseObjCMethodReplacement() const;
|
|
|
|
/// Should we use native dynamic function replacement mechanism for this decl.
|
|
/// This is all native dynamic methods except for `@objc dynamic` methods in
|
|
/// generic classes (see above).
|
|
bool shouldUseNativeMethodReplacement() const;
|
|
|
|
/// Is this a native dynamic function replacement based replacement.
|
|
/// This is all @_dynamicReplacement(for:) of native functions and @objc
|
|
/// dynamic methods on generic classes (see above).
|
|
bool isNativeMethodReplacement() const;
|
|
|
|
/// Returns if this declaration has more visible formal access than 'other'.
|
|
bool isMoreVisibleThan(ValueDecl *other) const;
|
|
|
|
/// Set whether this type is 'dynamic' or not.
|
|
void setIsDynamic(bool value);
|
|
|
|
/// Whether the 'dynamic' bit has been computed already.
|
|
bool isDynamicComputed() const {
|
|
return LazySemanticInfo.isDynamicComputed;
|
|
}
|
|
|
|
/// Returns true if this decl can be found by id-style dynamic lookup.
|
|
bool canBeAccessedByDynamicLookup() const;
|
|
|
|
/// Returns true if this declaration has an implicitly unwrapped optional
|
|
/// result. The precise meaning depends on the declaration kind:
|
|
/// - for properties, the value is IUO
|
|
/// - for subscripts, the element type is IUO
|
|
/// - for functions, the result type is IUO
|
|
/// - for constructors, the failability kind is IUO
|
|
bool isImplicitlyUnwrappedOptional() const;
|
|
|
|
/// Should only be set on imported and deserialized declarations; parsed
|
|
/// declarations compute this lazily via a request.
|
|
void setImplicitlyUnwrappedOptional(bool isIUO) {
|
|
LazySemanticInfo.isIUOComputed = 1;
|
|
LazySemanticInfo.isIUO = isIUO;
|
|
}
|
|
|
|
/// Returns the protocol requirements that this decl conforms to.
|
|
ArrayRef<ValueDecl *>
|
|
getSatisfiedProtocolRequirements(bool Sorted = false) const;
|
|
|
|
/// Determines the kind of access that should be performed by a
|
|
/// DeclRefExpr or MemberRefExpr use of this value in the specified
|
|
/// context.
|
|
///
|
|
/// \param DC The declaration context.
|
|
///
|
|
/// \param isAccessOnSelf Whether this is a member access on the implicit
|
|
/// 'self' declaration of the declaration context.
|
|
AccessSemantics getAccessSemanticsFromContext(const DeclContext *DC,
|
|
bool isAccessOnSelf) const;
|
|
|
|
/// Determines if a reference to this declaration from a nested function
|
|
/// should be treated like a capture of a local value.
|
|
bool isLocalCapture() const;
|
|
|
|
/// Print a reference to the given declaration.
|
|
std::string printRef() const;
|
|
|
|
/// Dump a reference to the given declaration.
|
|
void dumpRef(raw_ostream &os) const;
|
|
|
|
/// Dump a reference to the given declaration.
|
|
SWIFT_DEBUG_DUMPER(dumpRef());
|
|
|
|
/// Returns true if the declaration is a static member of a type.
|
|
///
|
|
/// This is not necessarily the opposite of "isInstanceMember()". Both
|
|
/// predicates will be false for declarations that either categorically
|
|
/// can't be "static" or are in a context where "static" doesn't make sense.
|
|
bool isStatic() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_ValueDecl &&
|
|
D->getKind() <= DeclKind::Last_ValueDecl;
|
|
}
|
|
|
|
/// True if this is a C function that was imported as a member of a type in
|
|
/// Swift.
|
|
bool isImportAsMember() const;
|
|
|
|
/// Returns true if the declaration's interface type is a function type with a
|
|
/// curried self parameter.
|
|
bool hasCurriedSelf() const;
|
|
|
|
/// Returns true if the declaration has a parameter list associated with it.
|
|
///
|
|
/// Note that not all declarations with function interface types have
|
|
/// parameter lists, for example an enum element without associated values.
|
|
bool hasParameterList() const;
|
|
|
|
/// Returns the parameter list directly associated with this declaration,
|
|
/// or `nullptr` if there is none.
|
|
///
|
|
/// Note that some declarations with function interface types do not have
|
|
/// parameter lists. For example, an enum element without associated values.
|
|
ParameterList *getParameterList();
|
|
const ParameterList *getParameterList() const;
|
|
|
|
/// Returns the number of curry levels in the declaration's interface type.
|
|
unsigned getNumCurryLevels() const;
|
|
|
|
/// Get the decl for this value's opaque result type, if it has one.
|
|
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;
|
|
|
|
/// Gets the decl for this value's opaque result type if it has already been
|
|
/// computed, or `nullopt` otherwise. This should only be used for dumping.
|
|
std::optional<OpaqueTypeDecl *> getCachedOpaqueResultTypeDecl() const;
|
|
|
|
/// Get the representative for this value's opaque result type, if it has one.
|
|
/// Returns a `TypeRepr` instead of an `OpaqueReturnTypeRepr` because 'some'
|
|
/// types might appear in one or more structural positions, e.g. (some P,
|
|
/// some Q), or we might have a `NamedOpaqueReturnTypeRepr`.
|
|
TypeRepr *getOpaqueResultTypeRepr() const;
|
|
|
|
/// Get the representative for this value's result type, if it has one.
|
|
TypeRepr *getResultTypeRepr() const;
|
|
|
|
/// Retrieve the attribute associating this declaration with a
|
|
/// result builder, if there is one.
|
|
CustomAttr *getAttachedResultBuilder() const;
|
|
|
|
/// Retrieve the @resultBuilder type attached to this declaration,
|
|
/// if there is one.
|
|
Type getResultBuilderType() const;
|
|
|
|
/// If this value or its backing storage is annotated
|
|
/// @_dynamicReplacement(for: ...), compute the original declaration
|
|
/// that this declaration dynamically replaces.
|
|
ValueDecl *getDynamicallyReplacedDecl() const;
|
|
|
|
/// Performs a request to look up the decl that this decl has been renamed to
|
|
/// if `attr` indicates that it has been renamed.
|
|
ValueDecl *getRenamedDecl(const AvailableAttr *attr) const;
|
|
|
|
/// Directly sets the renamed decl corresponding to `attr`. This should only
|
|
/// be used when synthesizing an `AvailableAttr`, before calling
|
|
/// `getRenamedDecl()`.
|
|
void setRenamedDecl(const AvailableAttr *attr, ValueDecl *renameDecl) const;
|
|
};
|
|
|
|
/// This is a common base class for declarations which declare a type.
|
|
class TypeDecl : public ValueDecl {
|
|
private:
|
|
ArrayRef<InheritedEntry> Inherited;
|
|
|
|
protected:
|
|
TypeDecl(DeclKind K, llvm::PointerUnion<DeclContext *, ASTContext *> context,
|
|
Identifier name, SourceLoc NameLoc,
|
|
ArrayRef<InheritedEntry> inherited) :
|
|
ValueDecl(K, context, name, NameLoc), Inherited(inherited) {}
|
|
|
|
friend class InheritedTypes;
|
|
|
|
public:
|
|
Identifier getName() const { return getBaseIdentifier(); }
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
return hasName() ? getBaseIdentifier().str() : "_";
|
|
}
|
|
|
|
/// The type of this declaration's values. For the type of the
|
|
/// declaration itself, use getInterfaceType(), which returns a
|
|
/// metatype.
|
|
Type getDeclaredInterfaceType() const;
|
|
|
|
/// Retrieve the set of protocols that this type inherits (i.e,
|
|
/// explicitly conforms to).
|
|
InheritedTypes getInherited() const { return InheritedTypes(this); }
|
|
|
|
void setInherited(ArrayRef<InheritedEntry> i) { Inherited = i; }
|
|
|
|
struct CanBeInvertible {
|
|
/// Indicates how "strongly" a TypeDecl will conform to an invertible
|
|
/// protocol. Supports inequality comparisons and casts to bool.
|
|
enum Result : unsigned {
|
|
Never = 0, // Never conforms.
|
|
Conditionally = 1, // Conditionally conforms.
|
|
Always = 2, // Always conforms.
|
|
};
|
|
};
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_TypeDecl &&
|
|
D->getKind() <= DeclKind::Last_TypeDecl;
|
|
}
|
|
|
|
/// Compute an ordering between two type declarations that is ABI-stable.
|
|
static int compare(const TypeDecl *type1, const TypeDecl *type2);
|
|
|
|
/// Compute an ordering between two type declarations that is ABI-stable.
|
|
/// This version takes a pointer-to-a-pointer for use with
|
|
/// llvm::array_pod_sort() and similar.
|
|
template<typename T>
|
|
static int compare(T * const* type1, T * const* type2) {
|
|
return compare(*type1, *type2);
|
|
}
|
|
};
|
|
|
|
/// A type declaration that have generic parameters attached to it. Because
|
|
/// it has these generic parameters, it is always a DeclContext.
|
|
class GenericTypeDecl : public GenericContext, public TypeDecl {
|
|
public:
|
|
GenericTypeDecl(DeclKind K, DeclContext *DC,
|
|
Identifier name, SourceLoc nameLoc,
|
|
ArrayRef<InheritedEntry> inherited,
|
|
GenericParamList *GenericParams);
|
|
|
|
// Resolve ambiguity due to multiple base classes.
|
|
using TypeDecl::getASTContext;
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
using TypeDecl::getDeclaredInterfaceType;
|
|
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_GenericTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_GenericTypeDecl;
|
|
}
|
|
};
|
|
|
|
/// OpaqueTypeDecl - This is a declaration of an opaque type. The opaque type
|
|
/// is formally equivalent to its underlying type, but abstracts it away from
|
|
/// clients of the opaque type, only exposing the type as something conforming
|
|
/// to a given set of constraints.
|
|
///
|
|
/// An `OpaqueTypeDecl` is formed implicitly when a declaration is written with
|
|
/// an opaque result type, as in the following example:
|
|
///
|
|
/// func foo() -> some SignedInteger { return 1 }
|
|
///
|
|
/// The declared type uses a special kind of archetype type to represent
|
|
/// abstracted types, e.g. `(some P, some Q)` becomes `((opaque archetype 0),
|
|
/// (opaque archetype 1))`.
|
|
class OpaqueTypeDecl final :
|
|
public GenericTypeDecl,
|
|
private llvm::TrailingObjects<OpaqueTypeDecl, TypeRepr *> {
|
|
friend TrailingObjects;
|
|
friend class UniqueUnderlyingTypeSubstitutionsRequest;
|
|
|
|
public:
|
|
/// A set of substitutions that represents a possible underlying type iff
|
|
/// associated set of availability conditions is met.
|
|
class ConditionallyAvailableSubstitutions;
|
|
|
|
private:
|
|
/// The original declaration that "names" the opaque type. Although a specific
|
|
/// opaque type cannot be explicitly named, opaque types can propagate
|
|
/// arbitrarily through expressions, so we need to know *which* opaque type is
|
|
/// propagated.
|
|
///
|
|
/// The bit indicates whether there are any trailing
|
|
/// OpaqueReturnTypeReprs.
|
|
llvm::PointerIntPair<ValueDecl *, 1>
|
|
NamingDeclAndHasOpaqueReturnTypeRepr;
|
|
|
|
/// The generic signature of the opaque interface to the type. This is the
|
|
/// outer generic signature with added generic parameters representing the
|
|
/// abstracted underlying types.
|
|
GenericSignature OpaqueInterfaceGenericSignature;
|
|
|
|
/// If known, the underlying type and conformances of the opaque type,
|
|
/// expressed as a SubstitutionMap for the opaque interface generic signature.
|
|
/// This maps types in the interface generic signature to the outer generic
|
|
/// signature of the original declaration.
|
|
std::optional<SubstitutionMap> UniqueUnderlyingType;
|
|
|
|
/// A set of substitutions which are used based on the availability
|
|
/// checks performed at runtime. This set of only populated if there
|
|
/// is no single unique underlying type for this opaque type declaration.
|
|
///
|
|
/// It always contains one or more conditionally available substitutions
|
|
/// followed by a universally available type used as a fallback.
|
|
std::optional<MutableArrayRef<ConditionallyAvailableSubstitutions *>>
|
|
ConditionallyAvailableTypes = std::nullopt;
|
|
|
|
mutable Identifier OpaqueReturnTypeIdentifier;
|
|
|
|
struct {
|
|
unsigned UniqueUnderlyingTypeComputed : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams,
|
|
DeclContext *DC,
|
|
GenericSignature OpaqueInterfaceGenericSignature,
|
|
ArrayRef<TypeRepr *> OpaqueReturnTypeReprs);
|
|
|
|
unsigned getNumOpaqueReturnTypeReprs() const {
|
|
return NamingDeclAndHasOpaqueReturnTypeRepr.getInt()
|
|
? getOpaqueGenericParams().size()
|
|
: 0;
|
|
}
|
|
|
|
size_t numTrailingObjects(OverloadToken<OpaqueReturnTypeRepr *>) const {
|
|
return getNumOpaqueReturnTypeReprs();
|
|
}
|
|
|
|
public:
|
|
static OpaqueTypeDecl *get(
|
|
ValueDecl *NamingDecl, GenericParamList *GenericParams,
|
|
DeclContext *DC,
|
|
GenericSignature OpaqueInterfaceGenericSignature,
|
|
ArrayRef<TypeRepr *> OpaqueReturnTypeReprs);
|
|
|
|
ValueDecl *getNamingDecl() const {
|
|
return NamingDeclAndHasOpaqueReturnTypeRepr.getPointer();
|
|
}
|
|
|
|
void setNamingDecl(ValueDecl *D) {
|
|
assert(!getNamingDecl() && "already have naming decl");
|
|
NamingDeclAndHasOpaqueReturnTypeRepr.setPointer(D);
|
|
}
|
|
|
|
/// Is this opaque type the opaque return type of the given function?
|
|
///
|
|
/// This is more complex than just checking `getNamingDecl` because the
|
|
/// function could also be the getter of a storage declaration.
|
|
bool isOpaqueReturnTypeOf(const Decl *owner) const;
|
|
|
|
/// Get the ordinal of the anonymous opaque parameter of this decl with type
|
|
/// repr `repr`, as introduce implicitly by an occurrence of "some" in return
|
|
/// position e.g. `func f() -> some P`. Returns -1 if `repr` is not found.
|
|
std::optional<unsigned> getAnonymousOpaqueParamOrdinal(TypeRepr *repr) const;
|
|
|
|
GenericSignature getOpaqueInterfaceGenericSignature() const {
|
|
return OpaqueInterfaceGenericSignature;
|
|
}
|
|
|
|
/// Retrieve the generic parameters that represent the opaque types described by this opaque
|
|
/// type declaration.
|
|
ArrayRef<GenericTypeParamType *> getOpaqueGenericParams() const {
|
|
return OpaqueInterfaceGenericSignature.getInnermostGenericParams();
|
|
}
|
|
|
|
/// Whether the generic parameters of this opaque type declaration were
|
|
/// explicit, i.e., for named opaque result types.
|
|
bool hasExplicitGenericParams() const;
|
|
|
|
/// When the generic parameters were explicit, returns the generic parameter
|
|
/// corresponding to the given ordinal.
|
|
///
|
|
/// Otherwise, returns \c nullptr.
|
|
GenericTypeParamDecl *getExplicitGenericParam(unsigned ordinal) const;
|
|
|
|
/// Retrieve the buffer containing the opaque return type
|
|
/// representations that correspond to the opaque generic parameters.
|
|
ArrayRef<TypeRepr *> getOpaqueReturnTypeReprs() const {
|
|
return {
|
|
getTrailingObjects<TypeRepr *>(),
|
|
getNumOpaqueReturnTypeReprs()
|
|
};
|
|
}
|
|
|
|
/// Should the underlying type be visible to clients outside of the module?
|
|
bool exportUnderlyingType() const;
|
|
|
|
/// The substitutions that map the generic parameters of the opaque type to
|
|
/// the unique underlying types, when that information is known.
|
|
std::optional<SubstitutionMap> getUniqueUnderlyingTypeSubstitutions() const;
|
|
|
|
void setUniqueUnderlyingTypeSubstitutions(SubstitutionMap subs) {
|
|
assert(!UniqueUnderlyingType.has_value() && "resetting underlying type?!");
|
|
UniqueUnderlyingType = subs;
|
|
}
|
|
|
|
bool hasConditionallyAvailableSubstitutions() const {
|
|
return ConditionallyAvailableTypes.has_value();
|
|
}
|
|
|
|
ArrayRef<ConditionallyAvailableSubstitutions *>
|
|
getConditionallyAvailableSubstitutions() const {
|
|
assert(ConditionallyAvailableTypes);
|
|
return ConditionallyAvailableTypes.value();
|
|
}
|
|
|
|
void setConditionallyAvailableSubstitutions(
|
|
ArrayRef<ConditionallyAvailableSubstitutions *> substitutions);
|
|
|
|
// Opaque type decls are currently always implicit
|
|
SourceRange getSourceRange() const { return SourceRange(); }
|
|
|
|
// Get the identifier string that can be used to cross-reference unnamed
|
|
// opaque return types across files.
|
|
Identifier getOpaqueReturnTypeIdentifier() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::OpaqueType;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::OpaqueType;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using AvailabilityCondition = std::pair<VersionRange, bool>;
|
|
|
|
class ConditionallyAvailableSubstitutions final
|
|
: private llvm::TrailingObjects<
|
|
ConditionallyAvailableSubstitutions,
|
|
AvailabilityCondition> {
|
|
friend TrailingObjects;
|
|
|
|
unsigned NumAvailabilityConditions;
|
|
|
|
SubstitutionMap Substitutions;
|
|
|
|
/// A type with limited availability described by the provided set
|
|
/// of availability conditions (with `and` relationship).
|
|
ConditionallyAvailableSubstitutions(
|
|
ArrayRef<AvailabilityCondition> availabilityContext,
|
|
SubstitutionMap substitutions)
|
|
: NumAvailabilityConditions(availabilityContext.size()),
|
|
Substitutions(substitutions) {
|
|
assert(!availabilityContext.empty());
|
|
std::uninitialized_copy(availabilityContext.begin(),
|
|
availabilityContext.end(),
|
|
getTrailingObjects<AvailabilityCondition>());
|
|
}
|
|
|
|
public:
|
|
ArrayRef<AvailabilityCondition> getAvailability() const {
|
|
return {getTrailingObjects<AvailabilityCondition>(), NumAvailabilityConditions};
|
|
}
|
|
|
|
SubstitutionMap getSubstitutions() const { return Substitutions; }
|
|
|
|
static ConditionallyAvailableSubstitutions *
|
|
get(ASTContext &ctx, ArrayRef<AvailabilityCondition> availabilityContext,
|
|
SubstitutionMap substitutions);
|
|
};
|
|
};
|
|
|
|
/// TypeAliasDecl - This is a declaration of a typealias, for example:
|
|
///
|
|
/// typealias Foo = Int
|
|
///
|
|
/// TypeAliasDecl's always have 'MetatypeType' type.
|
|
///
|
|
class TypeAliasDecl : public GenericTypeDecl {
|
|
friend class UnderlyingTypeRequest;
|
|
|
|
/// The location of the 'typealias' keyword
|
|
SourceLoc TypeAliasLoc;
|
|
|
|
/// The location of the equal '=' token
|
|
SourceLoc EqualLoc;
|
|
|
|
/// The end of the type, valid even when the type cannot be parsed
|
|
SourceLoc TypeEndLoc;
|
|
|
|
/// The location of the right-hand side of the typealias binding
|
|
TypeLoc UnderlyingTy;
|
|
|
|
public:
|
|
TypeAliasDecl(SourceLoc TypeAliasLoc, SourceLoc EqualLoc, Identifier Name,
|
|
SourceLoc NameLoc, GenericParamList *GenericParams,
|
|
DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return TypeAliasLoc; }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Returns the location of the equal '=' token
|
|
SourceLoc getEqualLoc() const {
|
|
return EqualLoc;
|
|
}
|
|
|
|
void setTypeEndLoc(SourceLoc e) { TypeEndLoc = e; }
|
|
|
|
/// Retrieve the TypeRepr corresponding to the parsed underlying type.
|
|
TypeRepr *getUnderlyingTypeRepr() const {
|
|
return UnderlyingTy.getTypeRepr();
|
|
}
|
|
void setUnderlyingTypeRepr(TypeRepr *repr) {
|
|
UnderlyingTy = repr;
|
|
}
|
|
|
|
/// Retrieve the interface type of the underlying type.
|
|
Type getUnderlyingType() const;
|
|
void setUnderlyingType(Type type);
|
|
|
|
/// Returns the interface type of the underlying type if computed, null
|
|
/// otherwise. Should only be used for dumping.
|
|
Type getCachedUnderlyingType() const { return UnderlyingTy.getType(); }
|
|
|
|
/// For generic typealiases, return the unbound generic type.
|
|
///
|
|
/// Since UnboundGenericType is on its way out, so is this method. Try to
|
|
/// avoid introducing new callers if possible. Instead of passing around
|
|
/// an UnboundGenericType, considering passing around the Decl itself
|
|
/// instead.
|
|
UnboundGenericType *getUnboundGenericType() const;
|
|
|
|
/// Retrieve a sugared interface type containing the structure of the interface
|
|
/// type before any semantic validation has occurred.
|
|
Type getStructuralType() const;
|
|
|
|
/// Whether the typealias forwards perfectly to its underlying type.
|
|
///
|
|
/// If true, this typealias was created by ClangImporter to preserve source
|
|
/// compatibility with a previous language version's name for a type. Many
|
|
/// checks in Sema look through compatibility aliases even when they would
|
|
/// operate on other typealiases.
|
|
///
|
|
/// \warning This has absolutely nothing to do with the Objective-C
|
|
/// \c compatibility_alias keyword.
|
|
bool isCompatibilityAlias() const {
|
|
return Bits.TypeAliasDecl.IsCompatibilityAlias;
|
|
}
|
|
|
|
/// Sets whether the typealias forwards perfectly to its underlying type.
|
|
///
|
|
/// Marks this typealias as having been created by ClangImporter to preserve
|
|
/// source compatibility with a previous language version's name for a type.
|
|
/// Many checks in Sema look through compatibility aliases even when they
|
|
/// would operate on other typealiases.
|
|
///
|
|
/// \warning This has absolutely nothing to do with the Objective-C
|
|
/// \c compatibility_alias keyword.
|
|
void markAsCompatibilityAlias(bool newValue = true) {
|
|
Bits.TypeAliasDecl.IsCompatibilityAlias = newValue;
|
|
}
|
|
|
|
/// Is this a special debugger variable?
|
|
bool isDebuggerAlias() const { return Bits.TypeAliasDecl.IsDebuggerAlias; }
|
|
void markAsDebuggerAlias(bool isDebuggerAlias) {
|
|
Bits.TypeAliasDecl.IsDebuggerAlias = isDebuggerAlias;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::TypeAlias;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::TypeAlias;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// A declaration of a generic type parameter.
|
|
///
|
|
/// A generic type parameter introduces a new, named type parameter along
|
|
/// with some set of requirements on any type argument used to realize this
|
|
/// type parameter. The requirements involve conformances to specific
|
|
/// protocols or inheritance from a specific class type.
|
|
///
|
|
/// In the following example, 'T' is a generic type parameter with the
|
|
/// requirement that the type argument conform to the 'Comparable' protocol.
|
|
///
|
|
/// \code
|
|
/// func min<T : Comparable>(x : T, y : T) -> T { ... }
|
|
/// \endcode
|
|
class GenericTypeParamDecl final
|
|
: public TypeDecl,
|
|
private llvm::TrailingObjects<GenericTypeParamDecl, TypeRepr *,
|
|
SourceLoc> {
|
|
friend TrailingObjects;
|
|
|
|
size_t numTrailingObjects(OverloadToken<TypeRepr *>) const {
|
|
return isOpaqueType() ? 1 : 0;
|
|
}
|
|
|
|
size_t numTrailingObjects(OverloadToken<SourceLoc>) const {
|
|
if (isParameterPack() || isValue()) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// Construct a new generic type parameter.
|
|
///
|
|
/// \param dc The DeclContext in which the generic type parameter's owner
|
|
/// occurs. This should later be overwritten with the actual declaration
|
|
/// context that owns the type parameter.
|
|
///
|
|
/// \param name The name of the generic parameter.
|
|
/// \param nameLoc The location of the name.
|
|
/// \param specifierLoc The location of the 'each' or 'let' keyword for pack
|
|
/// or value parameters.
|
|
/// \param depth The generic signature depth.
|
|
/// \param index The index of the parameter in the generic signature.
|
|
/// \param paramKind The kind of generic type parameter this is.
|
|
/// \param isOpaqueType Whether the generic parameter is written as an opaque
|
|
/// parameter e.g 'some Collection'.
|
|
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
|
|
///
|
|
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
|
|
SourceLoc specifierLoc, unsigned depth, unsigned index,
|
|
GenericTypeParamKind paramKind, bool isOpaqueType,
|
|
TypeRepr *opaqueTypeRepr);
|
|
|
|
/// Construct a new generic type parameter.
|
|
///
|
|
/// \param dc The DeclContext in which the generic type parameter's owner
|
|
/// occurs. This should later be overwritten with the actual declaration
|
|
/// context that owns the type parameter.
|
|
///
|
|
/// \param name The name of the generic parameter.
|
|
/// \param nameLoc The location of the name.
|
|
/// \param specifierLoc The location of the 'each' or 'let' keyword for pack
|
|
/// or value parameters.
|
|
/// \param depth The generic signature depth.
|
|
/// \param index The index of the parameter in the generic signature.
|
|
/// \param paramKind The kind of generic type parameter this is.
|
|
/// \param isOpaqueType Whether the generic parameter is written as an opaque
|
|
/// parameter e.g 'some Collection'.
|
|
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
|
|
///
|
|
static GenericTypeParamDecl *create(DeclContext *dc, Identifier name,
|
|
SourceLoc nameLoc, SourceLoc specifierLoc,
|
|
unsigned depth, unsigned index,
|
|
GenericTypeParamKind paramKind,
|
|
bool isOpaqueType,
|
|
TypeRepr *opaqueTypeRepr);
|
|
|
|
public:
|
|
static const unsigned InvalidDepth = 0xFFFF;
|
|
|
|
/// Construct a new generic type parameter. This should only be used by the
|
|
/// ClangImporter, use \c GenericTypeParamDecl::create[...] instead.
|
|
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
|
|
SourceLoc specifierLoc, unsigned depth, unsigned index,
|
|
GenericTypeParamKind paramKind)
|
|
: GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, depth, index,
|
|
paramKind, false, nullptr) {
|
|
}
|
|
|
|
/// Construct a deserialized generic type parameter.
|
|
///
|
|
/// \param dc The DeclContext in which the generic type parameter's owner
|
|
/// occurs. This should later be overwritten with the actual declaration
|
|
/// context that owns the type parameter.
|
|
///
|
|
/// \param name The name of the generic parameter.
|
|
/// \param depth The generic signature depth.
|
|
/// \param index The index of the parameter in the generic signature.
|
|
/// \param paramKind The kind of generic type parameter this is.
|
|
/// \param isOpaqueType Whether the generic parameter is written as an opaque
|
|
/// parameter e.g 'some Collection'.
|
|
///
|
|
static GenericTypeParamDecl *
|
|
createDeserialized(DeclContext *dc, Identifier name, unsigned depth,
|
|
unsigned index, GenericTypeParamKind paramKind,
|
|
bool isOpaqueType);
|
|
|
|
/// Construct a new parsed generic type parameter.
|
|
///
|
|
/// \param dc The DeclContext in which the generic type parameter's owner
|
|
/// occurs. This should later be overwritten with the actual declaration
|
|
/// context that owns the type parameter.
|
|
///
|
|
/// \param name The name of the generic parameter.
|
|
/// \param nameLoc The location of the name.
|
|
/// \param specifierLoc The location of the 'each' or 'let' keyword for pack
|
|
/// or value parameters.
|
|
/// \param index The index of the parameter in the generic signature.
|
|
/// \param paramKind The kind of generic type parameter this is.
|
|
///
|
|
static GenericTypeParamDecl *createParsed(DeclContext *dc, Identifier name,
|
|
SourceLoc nameLoc,
|
|
SourceLoc specifierLoc,
|
|
unsigned index,
|
|
GenericTypeParamKind paramKind);
|
|
|
|
/// Construct a new implicit generic type parameter.
|
|
///
|
|
/// \param dc The DeclContext in which the generic type parameter's owner
|
|
/// occurs. This should later be overwritten with the actual declaration
|
|
/// context that owns the type parameter.
|
|
///
|
|
/// \param name The name of the generic parameter.
|
|
/// \param depth The generic signature depth.
|
|
/// \param index The index of the parameter in the generic signature.
|
|
/// \param paramKind The kind of generic type parameter this is.
|
|
/// \param opaqueTypeRepr The TypeRepr of an opaque generic parameter.
|
|
/// \param nameLoc The location of the name.
|
|
/// \param specifierLoc The location of the 'each' or 'let' keyword for pack
|
|
/// or value parameters.
|
|
///
|
|
static GenericTypeParamDecl *
|
|
createImplicit(DeclContext *dc, Identifier name, unsigned depth,
|
|
unsigned index, GenericTypeParamKind paramKind,
|
|
TypeRepr *opaqueTypeRepr = nullptr, SourceLoc nameLoc = {},
|
|
SourceLoc specifierLoc = {});
|
|
|
|
/// The depth of this generic type parameter, i.e., the number of outer
|
|
/// levels of generic parameter lists that enclose this type parameter.
|
|
///
|
|
/// \code
|
|
/// struct X<T> {
|
|
/// func f<U>() { }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// Here 'T' has depth 0 and 'U' has depth 1. Both have index 0.
|
|
unsigned getDepth() const { return Bits.GenericTypeParamDecl.Depth; }
|
|
|
|
/// Set the depth of this generic type parameter.
|
|
///
|
|
/// \sa getDepth
|
|
void setDepth(unsigned depth) {
|
|
Bits.GenericTypeParamDecl.Depth = depth;
|
|
assert(Bits.GenericTypeParamDecl.Depth == depth && "Truncation");
|
|
}
|
|
|
|
/// The kind of generic type parameter this is.
|
|
GenericTypeParamKind getParamKind() const {
|
|
return (GenericTypeParamKind) Bits.GenericTypeParamDecl.ParamKind;
|
|
}
|
|
|
|
/// Returns \c true if this generic type parameter is declared as a type
|
|
/// parameter pack.
|
|
///
|
|
/// \code
|
|
/// func foo<each T>(_ : for each T) { }
|
|
/// struct Foo<each T> { }
|
|
/// \endcode
|
|
bool isParameterPack() const {
|
|
return getParamKind() == GenericTypeParamKind::Pack;
|
|
}
|
|
|
|
/// Returns \c true if this generic type parameter is declared as a value
|
|
/// type parameter.
|
|
///
|
|
/// \code
|
|
/// struct InlineArray<let count: Int, Element: ~Copyable>
|
|
/// \endcode
|
|
bool isValue() const {
|
|
return getParamKind() == GenericTypeParamKind::Value;
|
|
}
|
|
|
|
/// Returns the underlying value type associated with this generic value
|
|
/// parameter. E.g. if this is 'let N: Int' returns 'Int'.
|
|
Type getValueType() const;
|
|
|
|
/// Determine whether this generic parameter represents an opaque type.
|
|
///
|
|
/// \code
|
|
/// // "some P" is represented by a generic type parameter.
|
|
/// func f() -> [some P] { ... }
|
|
/// \endcode
|
|
bool isOpaqueType() const {
|
|
return Bits.GenericTypeParamDecl.IsOpaqueType;
|
|
}
|
|
|
|
/// Retrieve the opaque return type representation described by this
|
|
/// generic parameter, or NULL if any of the following are true:
|
|
/// - the generic parameter does not describe an opaque type
|
|
/// - the opaque type was introduced via the "named opaque parameters"
|
|
/// extension, meaning that it was specified explicitly
|
|
/// - the enclosing declaration was deserialized, in which case it lost
|
|
/// the source location information and has no type representation.
|
|
TypeRepr *getOpaqueTypeRepr() const {
|
|
if (!isOpaqueType())
|
|
return nullptr;
|
|
|
|
return *getTrailingObjects<TypeRepr *>();
|
|
}
|
|
|
|
/// The index of this generic type parameter within its generic parameter
|
|
/// list.
|
|
///
|
|
/// \code
|
|
/// struct X<T, U> {
|
|
/// func f<V>() { }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// Here 'T' and 'U' have indexes 0 and 1, respectively. 'V' has index 0.
|
|
unsigned getIndex() const { return Bits.GenericTypeParamDecl.Index; }
|
|
|
|
/// Retrieve either the 'each' keyword or the 'let' keyword location for this
|
|
/// generic parameter depending on if it's a parameter pack or a value.
|
|
SourceLoc getSpecifierLoc() const {
|
|
if (!isParameterPack() && !isValue())
|
|
return SourceLoc();
|
|
|
|
return *getTrailingObjects<SourceLoc>();
|
|
}
|
|
|
|
/// Retrieve the 'each' keyword location for a type parameter pack \c each T.
|
|
SourceLoc getEachLoc() const {
|
|
if (!isParameterPack())
|
|
return SourceLoc();
|
|
|
|
return *getTrailingObjects<SourceLoc>();
|
|
}
|
|
|
|
/// Retrieve the 'let' keyword location for a value parameter \c let N.
|
|
SourceLoc getLetLoc() const {
|
|
if (!isValue())
|
|
return SourceLoc();
|
|
|
|
return *getTrailingObjects<SourceLoc>();
|
|
}
|
|
|
|
SourceLoc getStartLoc() const { return getNameLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::GenericTypeParam;
|
|
}
|
|
};
|
|
|
|
/// A declaration of an associated type.
|
|
///
|
|
/// An associated type introduces a new, named type in a protocol that
|
|
/// can vary from one conforming type to the next. Associated types have a
|
|
/// set of requirements to which the type that replaces it much realize,
|
|
/// described via conformance to specific protocols, or inheritance from a
|
|
/// specific class type.
|
|
///
|
|
/// In the following example, 'Element' is an associated type with no
|
|
/// requirements.
|
|
///
|
|
/// \code
|
|
/// protocol Enumerator {
|
|
/// typealias Element
|
|
/// func getNext() -> Element?
|
|
/// }
|
|
/// \endcode
|
|
class AssociatedTypeDecl : public TypeDecl {
|
|
/// The location of the initial keyword.
|
|
SourceLoc KeywordLoc;
|
|
|
|
/// The default definition.
|
|
TypeLoc DefaultDefinition;
|
|
|
|
/// The where clause attached to the associated type.
|
|
TrailingWhereClause *TrailingWhere;
|
|
|
|
friend class DefaultDefinitionTypeRequest;
|
|
|
|
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc, TypeRepr *defaultDefinition,
|
|
TrailingWhereClause *trailingWhere);
|
|
|
|
public:
|
|
static AssociatedTypeDecl *createParsed(ASTContext &ctx, DeclContext *dc,
|
|
SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc,
|
|
TypeRepr *defaultDefinition,
|
|
TrailingWhereClause *trailingWhere);
|
|
|
|
static AssociatedTypeDecl *createDeserialized(
|
|
ASTContext &ctx, DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc, TrailingWhereClause *trailingWhere,
|
|
LazyMemberLoader *lazyLoader, uint64_t defaultDefinitionTypeData);
|
|
|
|
/// Get the protocol in which this associated type is declared.
|
|
ProtocolDecl *getProtocol() const {
|
|
return cast<ProtocolDecl>(getDeclContext());
|
|
}
|
|
|
|
/// Check if we have a default definition type.
|
|
bool hasDefaultDefinitionType() const {
|
|
// If we have a TypeRepr, return true immediately without kicking off
|
|
// a request.
|
|
return DefaultDefinition.getTypeRepr() || getDefaultDefinitionType();
|
|
}
|
|
|
|
/// Retrieve the default definition type.
|
|
Type getDefaultDefinitionType() const;
|
|
|
|
/// Retrieve the default definition type if computed, `None` otherwise.
|
|
///
|
|
/// \Note Should only be used for dumping.
|
|
std::optional<Type> getCachedDefaultDefinitionType() const;
|
|
|
|
private:
|
|
/// Set the computed default definition type.
|
|
void setDefaultDefinitionType(Type ty);
|
|
|
|
public:
|
|
/// Retrieve the default definition as written in the source.
|
|
TypeRepr *getDefaultDefinitionTypeRepr() const {
|
|
return DefaultDefinition.getTypeRepr();
|
|
}
|
|
|
|
/// Retrieve the trailing where clause for this associated type, if any.
|
|
TrailingWhereClause *getTrailingWhereClause() const { return TrailingWhere; }
|
|
|
|
/// Set the trailing where clause for this associated type.
|
|
void setTrailingWhereClause(TrailingWhereClause *trailingWhereClause) {
|
|
TrailingWhere = trailingWhereClause;
|
|
}
|
|
|
|
/// Retrieve the associated type "anchor", which is the associated type
|
|
/// declaration that will be used to describe this associated type in the
|
|
/// ABI.
|
|
///
|
|
/// The associated type "anchor" is an associated type that does not
|
|
/// override any other associated type. There may be several such associated
|
|
/// types; select one deterministically.
|
|
AssociatedTypeDecl *getAssociatedTypeAnchor() const;
|
|
|
|
/// Retrieve the (first) overridden associated type declaration, if any.
|
|
AssociatedTypeDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AssociatedTypeDecl>(
|
|
TypeDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Retrieve the set of associated types overridden by this associated
|
|
/// type.
|
|
llvm::TinyPtrVector<AssociatedTypeDecl *> getOverriddenDecls() const;
|
|
|
|
SourceLoc getStartLoc() const { return KeywordLoc; }
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::AssociatedType;
|
|
}
|
|
};
|
|
|
|
class MemberLookupTable;
|
|
class ObjCMethodLookupTable;
|
|
class ConformanceLookupTable;
|
|
|
|
// Kinds of pointer types.
|
|
enum PointerTypeKind : unsigned {
|
|
PTK_UnsafeMutableRawPointer,
|
|
PTK_UnsafeRawPointer,
|
|
PTK_UnsafeMutablePointer,
|
|
PTK_UnsafePointer,
|
|
PTK_AutoreleasingUnsafeMutablePointer,
|
|
};
|
|
|
|
static inline bool isRawPointerKind(PointerTypeKind PTK) {
|
|
switch (PTK) {
|
|
case PTK_UnsafeMutableRawPointer:
|
|
case PTK_UnsafeRawPointer:
|
|
return true;
|
|
case PTK_UnsafeMutablePointer:
|
|
case PTK_UnsafePointer:
|
|
case PTK_AutoreleasingUnsafeMutablePointer:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled PointerTypeKind in switch.");
|
|
}
|
|
|
|
// Kinds of buffer pointer types.
|
|
enum BufferPointerTypeKind : unsigned {
|
|
BPTK_UnsafeMutableRawBufferPointer,
|
|
BPTK_UnsafeRawBufferPointer,
|
|
BPTK_UnsafeMutableBufferPointer,
|
|
BPTK_UnsafeBufferPointer,
|
|
};
|
|
|
|
enum KeyPathTypeKind : unsigned char {
|
|
KPTK_AnyKeyPath,
|
|
KPTK_PartialKeyPath,
|
|
KPTK_KeyPath,
|
|
KPTK_WritableKeyPath,
|
|
KPTK_ReferenceWritableKeyPath
|
|
};
|
|
|
|
/// NominalTypeDecl - a declaration of a nominal type, like a struct.
|
|
class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
|
|
SourceRange Braces;
|
|
|
|
/// The first extension of this type.
|
|
ExtensionDecl *FirstExtension = nullptr;
|
|
|
|
/// The last extension of this type, used solely for efficient
|
|
/// insertion of new extensions.
|
|
ExtensionDecl *LastExtension = nullptr;
|
|
|
|
/// The generation at which we last loaded extensions.
|
|
unsigned ExtensionGeneration;
|
|
|
|
/// Prepare to traverse the list of extensions.
|
|
void prepareExtensions();
|
|
|
|
/// Retrieve the conformance loader (if any), and removing it in the
|
|
/// same operation. The caller is responsible for loading the
|
|
/// conformances.
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoader() {
|
|
if (!Bits.NominalTypeDecl.HasLazyConformances)
|
|
return { nullptr, 0 };
|
|
|
|
return takeConformanceLoaderSlow();
|
|
}
|
|
|
|
/// Slow path for \c takeConformanceLoader().
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoaderSlow();
|
|
|
|
/// A lookup table containing all of the members of this type and
|
|
/// its extensions, together with a bit indicating if the table
|
|
/// has been prepared.
|
|
///
|
|
/// The table itself is lazily constructed and updated when
|
|
/// lookupDirect() is called.
|
|
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;
|
|
|
|
/// Get the lookup table, lazily constructing an empty table if
|
|
/// necessary.
|
|
MemberLookupTable *getLookupTable();
|
|
|
|
/// Prepare the lookup table to make it ready for lookups.
|
|
/// Does nothing when called more than once.
|
|
void prepareLookupTable();
|
|
|
|
/// Note that we have added a member into the iterable declaration context,
|
|
/// so that it can also be added to the lookup table (if needed).
|
|
void addedMember(Decl *member);
|
|
|
|
/// Note that we have added an extension into the nominal type,
|
|
/// so that its members can eventually be added to the lookup table.
|
|
void addedExtension(ExtensionDecl *ext);
|
|
|
|
/// A lookup table used to find the protocol conformances of
|
|
/// a given nominal type.
|
|
mutable ConformanceLookupTable *ConformanceTable = nullptr;
|
|
|
|
/// Prepare the conformance table.
|
|
void prepareConformanceTable() const;
|
|
|
|
/// Returns the protocol requirements that \c Member conforms to.
|
|
ArrayRef<ValueDecl *>
|
|
getSatisfiedProtocolRequirementsForMember(const ValueDecl *Member,
|
|
bool Sorted) const;
|
|
|
|
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
|
|
|
|
/// Create the Objective-C method lookup table, or return \c false if this
|
|
/// kind of type cannot have Objective-C methods.
|
|
bool createObjCMethodLookup();
|
|
|
|
friend class ASTContext;
|
|
friend class MemberLookupTable;
|
|
friend class ConformanceLookupTable;
|
|
friend class ExtensionDecl;
|
|
friend class DeclContext;
|
|
friend class IterableDeclContext;
|
|
friend class DirectLookupRequest;
|
|
friend class LookupAllConformancesInContextRequest;
|
|
friend ArrayRef<ValueDecl *>
|
|
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
|
|
|
|
protected:
|
|
Type DeclaredTy;
|
|
Type DeclaredInterfaceTy;
|
|
|
|
NominalTypeDecl(DeclKind K, DeclContext *DC, Identifier name,
|
|
SourceLoc NameLoc,
|
|
ArrayRef<InheritedEntry> inherited,
|
|
GenericParamList *GenericParams) :
|
|
GenericTypeDecl(K, DC, name, NameLoc, inherited, GenericParams),
|
|
IterableDeclContext(IterableDeclContextKind::NominalTypeDecl)
|
|
{
|
|
Bits.NominalTypeDecl.AddedImplicitInitializers = false;
|
|
ExtensionGeneration = 0;
|
|
Bits.NominalTypeDecl.HasLazyConformances = false;
|
|
Bits.NominalTypeDecl.IsComputingSemanticMembers = false;
|
|
}
|
|
|
|
friend class ProtocolType;
|
|
|
|
public:
|
|
using GenericTypeDecl::getASTContext;
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
/// Returns whether this declaration is resilient at the definition site, i.e.
|
|
/// must be accessed resiliently even when its defining module is built
|
|
/// non-resiliently.
|
|
///
|
|
/// This is used for diagnostics, because we do not want a behavior
|
|
/// change between builds with resilience enabled and disabled.
|
|
bool isFormallyResilient() const;
|
|
|
|
/// Returns whether this decl is resilient at the definition site
|
|
/// \c isFormallyResilient or whether its defining module
|
|
/// is built resiliently.
|
|
bool isResilient() const;
|
|
|
|
/// True if the decl is resilient AND also its defining module does
|
|
/// _not_ allow non-resilient access; the module can allow such access
|
|
/// if package optimization is enabled so its client modules within the
|
|
/// same package can have a direct access to this decl even if it's
|
|
/// resilient.
|
|
bool isStrictlyResilient() const;
|
|
|
|
/// Returns whether this decl is accessed non/resiliently at the _use_ site
|
|
/// in \p accessingModule, depending on \p expansion.
|
|
///
|
|
/// If \p expansion is maximal, the decl could be treated as non-resilient
|
|
/// even though the decl is resilient by definition or its defining module is built
|
|
/// resiliently. For example, if accessing a decl defined in the same module or
|
|
/// another module in the same package as the \p accessingModule, the
|
|
/// decl could be treated as non-resilient (with package optimization enabled in
|
|
/// case of different modules); this enables bypassing resilience checks at the
|
|
/// use site so the decl can be accessed directly.
|
|
///
|
|
/// \p accessingModule The module from which this decl is accessed. Might
|
|
/// be the same module as its defining module.
|
|
/// \p expansion Used to determine whether non-resilience / direct access
|
|
/// to this decl is possible.
|
|
bool isResilient(ModuleDecl *accessingModule,
|
|
ResilienceExpansion expansion) const;
|
|
|
|
/// Determine whether we have already attempted to add any
|
|
/// implicitly-defined initializers to this declaration.
|
|
bool addedImplicitInitializers() const {
|
|
return Bits.NominalTypeDecl.AddedImplicitInitializers;
|
|
}
|
|
|
|
/// Note that we have attempted to add implicit initializers.
|
|
void setAddedImplicitInitializers() {
|
|
Bits.NominalTypeDecl.AddedImplicitInitializers = true;
|
|
}
|
|
|
|
/// getDeclaredType - Retrieve the type declared by this entity, without
|
|
/// any generic parameters bound if this is a generic type.
|
|
///
|
|
/// Since UnboundGenericType is on its way out, so is this method. Try to
|
|
/// avoid introducing new callers if possible. Instead of passing around
|
|
/// an UnboundGenericType, considering passing around the Decl itself
|
|
/// instead.
|
|
Type getDeclaredType() const;
|
|
|
|
/// getDeclaredInterfaceType - Retrieve the type declared by this entity, with
|
|
/// generic parameters bound if this is a generic type.
|
|
Type getDeclaredInterfaceType() const;
|
|
|
|
/// Add a new extension to this nominal type.
|
|
void addExtension(ExtensionDecl *extension);
|
|
|
|
/// Add a member to this decl's lookup table.
|
|
///
|
|
/// Calls "prepareLookupTable" as a side effect.
|
|
void addMemberToLookupTable(Decl *member);
|
|
|
|
/// Retrieve the set of extensions of this type.
|
|
ExtensionRange getExtensions();
|
|
|
|
/// Retrieve the extension most recently added to this type. Helpful to
|
|
/// determine if an extension has been added.
|
|
ExtensionDecl *getLastExtension() const {
|
|
return LastExtension;
|
|
}
|
|
|
|
/// Special-behaviour flags passed to lookupDirect()
|
|
enum class LookupDirectFlags {
|
|
/// Whether to include @_implements members.
|
|
/// Used by conformance-checking to find special @_implements members.
|
|
IncludeAttrImplements = 1 << 0,
|
|
/// Whether to exclude members of macro expansions.
|
|
ExcludeMacroExpansions = 1 << 1,
|
|
/// If @abi attributes are present, return the decls representing the ABI,
|
|
/// not the API.
|
|
ABIProviding = 1 << 2,
|
|
};
|
|
|
|
/// Find all of the declarations with the given name within this nominal type
|
|
/// and its extensions.
|
|
///
|
|
/// This routine does not look into superclasses, nor does it consider
|
|
/// protocols to which the nominal type conforms. Furthermore, the resulting
|
|
/// set of declarations has not been filtered for visibility, nor have
|
|
/// overridden declarations been removed.
|
|
TinyPtrVector<ValueDecl *> lookupDirect(DeclName name, SourceLoc loc = SourceLoc(),
|
|
OptionSet<LookupDirectFlags> flags =
|
|
OptionSet<LookupDirectFlags>());
|
|
|
|
/// Find the distributed actor system instance of this distributed actor.
|
|
VarDecl *getDistributedActorSystemProperty() const;
|
|
|
|
/// Find, or potentially synthesize, the implicit 'id' property of this actor.
|
|
VarDecl *getDistributedActorIDProperty() const;
|
|
|
|
/// Find the 'RemoteCallTarget.init(_:)' initializer function.
|
|
ConstructorDecl *getDistributedRemoteCallTargetInitFunction() const;
|
|
|
|
/// Find the 'RemoteCallArgument(label:name:value:)' initializer function.
|
|
ConstructorDecl *getDistributedRemoteCallArgumentInitFunction() const;
|
|
|
|
/// Get the move-only `enqueue(ExecutorJob)` protocol requirement function on the `Executor` protocol.
|
|
AbstractFunctionDecl *getExecutorOwnedEnqueueFunction() const;
|
|
/// This method should be deprecated and removed
|
|
/// Get the move-only `enqueue(Job)` protocol requirement function on the `Executor` protocol.
|
|
AbstractFunctionDecl *getExecutorLegacyOwnedEnqueueFunction() const;
|
|
/// Get the move-only `enqueue(UnownedJob)` protocol requirement function on the `Executor` protocol.
|
|
AbstractFunctionDecl *getExecutorLegacyUnownedEnqueueFunction() const;
|
|
|
|
/// Collect the set of protocols to which this type should implicitly
|
|
/// conform, such as AnyObject (for classes).
|
|
void getImplicitProtocols(SmallVectorImpl<ProtocolDecl *> &protocols);
|
|
|
|
/// Look for conformances of this nominal type to the given
|
|
/// protocol.
|
|
///
|
|
/// \param protocol The protocol whose conformance is requested.
|
|
/// \param conformances Will be populated with the set of protocol
|
|
/// conformances found for this protocol.
|
|
///
|
|
/// \returns true if any conformances were found.
|
|
bool lookupConformance(
|
|
ProtocolDecl *protocol,
|
|
SmallVectorImpl<ProtocolConformance *> &conformances) const;
|
|
|
|
/// Retrieve all of the protocols that this nominal type conforms to.
|
|
///
|
|
/// \param sorted Whether to sort the protocols in canonical order.
|
|
SmallVector<ProtocolDecl *, 2> getAllProtocols(bool sorted = false) const;
|
|
|
|
/// Retrieve all of the protocol conformances for this nominal type.
|
|
SmallVector<ProtocolConformance *, 2> getAllConformances(
|
|
bool sorted = false) const;
|
|
|
|
/// Register an externally-created protocol conformance in the
|
|
/// conformance lookup table.
|
|
///
|
|
/// This is used by deserialization of module files to report
|
|
/// conformances.
|
|
void registerProtocolConformance(NormalProtocolConformance *conformance,
|
|
bool synthesized = false);
|
|
|
|
void setConformanceLoader(LazyMemberLoader *resolver, uint64_t contextData);
|
|
|
|
/// Look in this type and its extensions (but not any of its protocols or
|
|
/// superclasses) for declarations with a given Objective-C selector.
|
|
///
|
|
/// Note that this can find methods, initializers, deinitializers,
|
|
/// getters, and setters.
|
|
///
|
|
/// \param selector The Objective-C selector of the method we're
|
|
/// looking for.
|
|
///
|
|
/// \param isInstance Whether we are looking for an instance method
|
|
/// (vs. a class method).
|
|
TinyPtrVector<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
|
|
bool isInstance);
|
|
|
|
/// Record the presence of an @objc method with the given selector. No-op if
|
|
/// the type is of a kind which cannot contain @objc methods.
|
|
void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector);
|
|
|
|
/// Is this the decl for Optional<T>?
|
|
bool isOptionalDecl() const;
|
|
|
|
/// Is this a key path type?
|
|
std::optional<KeyPathTypeKind> getKeyPathTypeKind() const;
|
|
|
|
/// Retrieve information about this type as a property wrapper.
|
|
PropertyWrapperTypeInfo getPropertyWrapperTypeInfo() const;
|
|
|
|
/// Return a collection of the stored member variables of this type.
|
|
ArrayRef<VarDecl *> getStoredProperties() const;
|
|
|
|
/// Return a collection of all properties with init accessors in
|
|
/// this type.
|
|
ArrayRef<VarDecl *> getInitAccessorProperties() const;
|
|
|
|
/// Return a collection of all properties that will be part of the memberwise
|
|
/// initializer.
|
|
ArrayRef<VarDecl *> getMemberwiseInitProperties() const;
|
|
|
|
/// Establish a mapping between properties that could be iniitalized
|
|
/// via other properties by means of init accessors. This mapping is
|
|
/// one-to-many because we allow intersecting `initializes(...)`.
|
|
void collectPropertiesInitializableByInitAccessors(
|
|
std::multimap<VarDecl *, VarDecl *> &result) const;
|
|
|
|
/// Return a collection of the stored member variables of this type, along
|
|
/// with placeholders for unimportable stored properties.
|
|
ArrayRef<Decl *> getStoredPropertiesAndMissingMemberPlaceholders() const;
|
|
|
|
/// Whether this nominal type qualifies as an actor, meaning that it is
|
|
/// either an actor type or a protocol whose `Self` type conforms to the
|
|
/// `Actor` protocol.
|
|
bool isActor() const;
|
|
|
|
/// Whether this nominal type qualifies as a distributed actor, meaning that
|
|
/// it is either a distributed actor or a DistributedActor constrained protocol.
|
|
bool isDistributedActor() const;
|
|
|
|
/// Whether this nominal type qualifies as any actor (plain or distributed).
|
|
bool isAnyActor() const;
|
|
|
|
/// Whether this nominal type is the `MainActor` global actor.
|
|
bool isMainActor() const;
|
|
|
|
/// Return the range of semantics attributes attached to this NominalTypeDecl.
|
|
auto getSemanticsAttrs() const
|
|
-> decltype(getAttrs().getSemanticsAttrs()) {
|
|
return getAttrs().getSemanticsAttrs();
|
|
}
|
|
|
|
bool hasSemanticsAttr(StringRef attrValue) const {
|
|
return getAttrs().hasSemanticsAttr(attrValue);
|
|
}
|
|
|
|
/// Returns true if we should emit assembly vision remarks on all methods of
|
|
/// this nominal type.
|
|
bool shouldEmitAssemblyVisionRemarksOnMethods() const {
|
|
return getAttrs().hasAttribute<EmitAssemblyVisionRemarksAttr>();
|
|
}
|
|
|
|
/// Whether this declaration has a synthesized memberwise initializer.
|
|
bool hasMemberwiseInitializer() const;
|
|
|
|
/// Retrieves the synthesized memberwise initializer for this declaration,
|
|
/// or \c nullptr if it does not have one.
|
|
ConstructorDecl *getMemberwiseInitializer() const;
|
|
|
|
/// Retrieves the effective memberwise initializer for this declaration, or
|
|
/// \c nullptr if it does not have one.
|
|
///
|
|
/// An effective memberwise initializer is either a synthesized memberwise
|
|
/// initializer or a user-defined initializer with the same type.
|
|
///
|
|
/// The access level of the memberwise initializer is set to the minimum of:
|
|
/// - Public, by default. This enables public nominal types to have public
|
|
/// memberwise initializers.
|
|
/// - The `public` default is important for synthesized member types, e.g.
|
|
/// `TangentVector` structs synthesized during `Differentiable` derived
|
|
/// conformances. Manually extending these types to define a public
|
|
/// memberwise initializer causes a redeclaration error.
|
|
/// - The minimum access level of memberwise-initialized properties in the
|
|
/// nominal type declaration.
|
|
///
|
|
/// Effective memberwise initializers are used only by derived conformances
|
|
/// for `Self`-returning protocol requirements like `AdditiveArithmetic.+`.
|
|
/// Such derived conformances require memberwise initialization.
|
|
ConstructorDecl *getEffectiveMemberwiseInitializer();
|
|
|
|
/// Whether this declaration has a synthesized zero parameter default
|
|
/// initializer.
|
|
bool hasDefaultInitializer() const;
|
|
|
|
bool isTypeErasedGenericClass() const;
|
|
|
|
/// Retrieves the synthesized zero parameter default initializer for this
|
|
/// declaration, or \c nullptr if it doesn't have one.
|
|
ConstructorDecl *getDefaultInitializer() const;
|
|
|
|
/// Force the synthesis of all members named \c member requiring semantic
|
|
/// analysis and install them in the member list of this nominal type.
|
|
///
|
|
/// \Note The use of this method in the compiler signals an architectural
|
|
/// problem with the caller. Use \c TypeChecker::lookup* instead of
|
|
/// introducing new usages.
|
|
///
|
|
/// FIXME: This method presents a problem with respect to the consistency
|
|
/// and idempotency of lookups in the compiler. If we instead had a model
|
|
/// where lookup requests would explicitly return semantic members or parsed
|
|
/// members this function could disappear.
|
|
void synthesizeSemanticMembersIfNeeded(DeclName member);
|
|
|
|
/// Retrieves the static 'shared' property of a global actor type, which
|
|
/// is used to extract the actor instance.
|
|
///
|
|
/// \returns the static 'shared' property for a global actor, or \c nullptr
|
|
/// for types that are not global actors.
|
|
VarDecl *getGlobalActorInstance() const;
|
|
|
|
/// Whether this type is a global actor, which can be used as an
|
|
/// attribute to decorate declarations for inclusion in the actor-isolated
|
|
/// state denoted by this type.
|
|
bool isGlobalActor() const {
|
|
return getGlobalActorInstance() != nullptr;
|
|
}
|
|
|
|
/// Return the `DestructorDecl` for a struct or enum's `deinit` declaration.
|
|
/// Returns null if the type is a class, or does not have a declared `deinit`.
|
|
DestructorDecl *getValueTypeDestructor();
|
|
|
|
/// Does a conformance for a given invertible protocol exist for this
|
|
/// type declaration.
|
|
CanBeInvertible::Result canConformTo(InvertibleProtocolKind kind) const;
|
|
|
|
/// "Does a conformance for Copyable exist for this type declaration?"
|
|
///
|
|
/// This doesn't mean that all instance of this type are Copyable, because
|
|
/// if a conditional conformance to Copyable exists, this method will return
|
|
/// true.
|
|
///
|
|
/// If you need a more precise answer, ask this Decl's corresponding
|
|
/// Type if it `isCopyable` instead of using this.
|
|
CanBeInvertible::Result canBeCopyable() const;
|
|
|
|
/// "Does a conformance for Escapable exist for this type declaration?"
|
|
///
|
|
/// This doesn't mean that all instance of this type are Escapable, because
|
|
/// if a conditional conformance to Escapable exists, this method will return
|
|
/// true.
|
|
///
|
|
/// If you need a more precise answer, ask this Decl's corresponding
|
|
/// Type if it `isEscapable` instead of using this.
|
|
CanBeInvertible::Result canBeEscapable() const;
|
|
|
|
bool suppressesConformance(KnownProtocolKind kp) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_NominalTypeDecl;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_NominalTypeDecl;
|
|
}
|
|
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
return C->getIterableContextKind()
|
|
== IterableDeclContextKind::NominalTypeDecl;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) { return true; }
|
|
static bool classof(const ExtensionDecl *D) { return false; }
|
|
};
|
|
|
|
/// This is the declaration of an enum.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// \code
|
|
/// enum Bool {
|
|
/// case false
|
|
/// case true
|
|
/// }
|
|
///
|
|
/// enum Optional<T> {
|
|
/// case none
|
|
/// case some(T)
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Bool" or "Optional" in the above example).
|
|
class EnumDecl final : public NominalTypeDecl {
|
|
SourceLoc EnumLoc;
|
|
|
|
enum SemanticInfoFlags : uint8_t {
|
|
// Is the raw type valid?
|
|
HasComputedRawType = 1 << 0,
|
|
// Is the complete set of (auto-incremented) raw values available?
|
|
HasFixedRawValues = 1 << 1,
|
|
// Is the complete set of raw values type checked?
|
|
HasFixedRawValuesAndTypes = 1 << 2,
|
|
};
|
|
OptionSet<SemanticInfoFlags> SemanticFlags;
|
|
|
|
friend class EnumRawValuesRequest;
|
|
friend class EnumRawTypeRequest;
|
|
|
|
public:
|
|
EnumDecl(SourceLoc EnumLoc, Identifier Name, SourceLoc NameLoc,
|
|
ArrayRef<InheritedEntry> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return EnumLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(EnumLoc, getBraces().End);
|
|
}
|
|
|
|
public:
|
|
/// A range for iterating the elements of an enum.
|
|
using ElementRange = DowncastFilterRange<EnumElementDecl, DeclRange>;
|
|
|
|
/// A range for iterating the elements of an enum that are available during
|
|
/// lowering.
|
|
using ElementRangeForLowering = OptionalTransformRange<
|
|
ElementRange, AvailableDuringLoweringDeclFilter<EnumElementDecl>>;
|
|
|
|
/// A range for iterating the cases of an enum.
|
|
using CaseRange = DowncastFilterRange<EnumCaseDecl, DeclRange>;
|
|
|
|
/// Return a range that iterates over all the elements of an enum.
|
|
ElementRange getAllElements() const {
|
|
return ElementRange(getMembers());
|
|
}
|
|
|
|
unsigned getNumElements() const {
|
|
auto eltRange = getAllElements();
|
|
return std::distance(eltRange.begin(), eltRange.end());
|
|
}
|
|
|
|
/// Returns a range that iterates over all the elements of an enum for which
|
|
/// \c isAvailableDuringLowering() is true.
|
|
ElementRangeForLowering getAllElementsForLowering() const {
|
|
return ElementRangeForLowering(
|
|
getAllElements(), AvailableDuringLoweringDeclFilter<EnumElementDecl>());
|
|
}
|
|
|
|
/// If this enum has a unique element, return it. A unique element can
|
|
/// either hold a value or not, and the existence of one unique element does
|
|
/// not imply the existence or non-existence of the opposite unique element.
|
|
EnumElementDecl *getUniqueElement(bool hasValue) const;
|
|
|
|
/// Return a range that iterates over all the cases of an enum.
|
|
CaseRange getAllCases() const {
|
|
return CaseRange(getMembers());
|
|
}
|
|
|
|
/// Insert all of the 'case' element declarations into a DenseSet.
|
|
void getAllElements(llvm::DenseSet<EnumElementDecl*> &elements) const {
|
|
for (auto elt : getAllElements())
|
|
elements.insert(elt);
|
|
}
|
|
|
|
/// Whether this enum has a raw value type that recursively references itself.
|
|
bool hasCircularRawValue() const;
|
|
|
|
/// Record that this enum has had all of its raw values computed.
|
|
void setHasFixedRawValues();
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Determine whether this enum declares a raw type in its inheritance clause.
|
|
bool hasRawType() const { return (bool)getRawType(); }
|
|
|
|
/// Retrieve the declared raw type of the enum from its inheritance clause,
|
|
/// or null if it has none.
|
|
Type getRawType() const;
|
|
|
|
/// Set the raw type of the enum from its inheritance clause.
|
|
void setRawType(Type rawType);
|
|
|
|
/// True if none of the enum cases have associated values.
|
|
///
|
|
/// Note that this is true for enums with absolutely no cases.
|
|
bool hasOnlyCasesWithoutAssociatedValues() const;
|
|
|
|
/// True if any of the enum cases have availability annotations.
|
|
///
|
|
/// Note that this is false for enums with absolutely no cases.
|
|
bool hasPotentiallyUnavailableCaseValue() const;
|
|
|
|
/// True if \c isAvailableDuringLowering() is false for any cases.
|
|
///
|
|
/// Note that this is false for enums with absolutely no cases.
|
|
bool hasCasesUnavailableDuringLowering() const;
|
|
|
|
/// True if the enum has cases.
|
|
bool hasCases() const {
|
|
return !getAllElements().empty();
|
|
}
|
|
|
|
/// True if the enum is marked 'indirect'.
|
|
bool isIndirect() const {
|
|
return getAttrs().hasAttribute<IndirectAttr>();
|
|
}
|
|
|
|
/// True if the enum can be exhaustively switched within \p useDC.
|
|
///
|
|
/// Note that this property is \e not necessarily true for all children of
|
|
/// \p useDC. In particular, an inlinable function does not get to switch
|
|
/// exhaustively over a non-exhaustive enum declared in the same module.
|
|
///
|
|
/// This is the predicate used when deciding if a switch statement needs a
|
|
/// default case. It should not be used for optimization or code generation.
|
|
///
|
|
/// \sa isEffectivelyExhaustive
|
|
bool isFormallyExhaustive(const DeclContext *useDC) const;
|
|
|
|
/// True if \s isFormallyExhaustive is true or the use site's module belongs
|
|
/// to the same package as this enum's defining module. If in same package
|
|
/// even though `isFormallyExhaustive` is false, we can skip requiring
|
|
/// `@unknown default` at the use site switch stmts because package modules
|
|
/// are expected to be built together whether they are resiliently built or
|
|
/// not. Used for diagnostics during typechecks only; if
|
|
/// `isFormallyExhaustive` is false, it should be reflected in SILgen.
|
|
bool treatAsExhaustiveForDiags(const DeclContext *useDC) const;
|
|
|
|
/// True if the enum can be exhaustively switched within a function defined
|
|
/// within \p M, with \p expansion specifying whether the function is
|
|
/// inlinable.
|
|
///
|
|
/// This is the predicate used when making optimization and code generation
|
|
/// decisions. It should not be used at the AST or semantic level.
|
|
///
|
|
/// \sa isFormallyExhaustive
|
|
bool isEffectivelyExhaustive(ModuleDecl *M,
|
|
ResilienceExpansion expansion) const;
|
|
};
|
|
|
|
/// StructDecl - This is the declaration of a struct, for example:
|
|
///
|
|
/// struct Complex { var R : Double, I : Double }
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Complex" in the above example).
|
|
class StructDecl final : public NominalTypeDecl {
|
|
SourceLoc StructLoc;
|
|
|
|
// We import C++ class templates as generic structs. Then when in Swift code
|
|
// we want to substitute generic parameters with actual arguments, we
|
|
// convert the arguments to C++ equivalents and ask Clang to instantiate the
|
|
// C++ template. Then we import the C++ class template instantiation
|
|
// as a non-generic structs with a name prefixed with `__CxxTemplateInst`.
|
|
//
|
|
// To reiterate:
|
|
// 1) We need to have a C++ class template declaration in the Clang AST. This
|
|
// declaration is simply imported from a Clang module.
|
|
// 2) We need a Swift generic struct in the Swift AST. This will provide
|
|
// template arguments to Clang.
|
|
// 3) We produce a C++ class template instantiation in the Clang AST
|
|
// using 1) and 2). This declaration does not exist in the Clang module
|
|
// AST initially in the general case, it's added there on instantiation.
|
|
// 4) We import the instantiation as a Swift struct, with the name prefixed
|
|
// with `__CxxTemplateInst`.
|
|
//
|
|
// This causes a problem for serialization/deserialization of the Swift
|
|
// module. Imagine the Swift struct from 4) is used in the function return
|
|
// type. We cannot just serialize the non generic Swift struct, because on
|
|
// deserialization we would need to find its backing Clang declaration
|
|
// (the C++ class template instantiation), and it won't be found in the
|
|
// general case. Only the C++ class template from step 1) is in the Clang
|
|
// AST.
|
|
//
|
|
// What we need is to serialize enough information to be
|
|
// able to instantiate C++ class template on deserialization. It turns out
|
|
// that all that information is conveniently covered by the BoundGenericType,
|
|
// which we store in this field. The field is set during the typechecking at
|
|
// the time when we instantiate the C++ class template.
|
|
//
|
|
// Alternative, and likely better solution long term, is to serialize the
|
|
// C++ class template instantiation into a synthetic Clang module, and load
|
|
// this Clang module on deserialization.
|
|
Type TemplateInstantiationType = Type();
|
|
|
|
public:
|
|
StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
|
|
ArrayRef<InheritedEntry> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return StructLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(StructLoc, getBraces().End);
|
|
}
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Struct;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Struct;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Struct;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Does this struct contain unreferenceable storage, such as C fields that
|
|
/// cannot be represented in Swift?
|
|
bool hasUnreferenceableStorage() const {
|
|
return Bits.StructDecl.HasUnreferenceableStorage;
|
|
}
|
|
|
|
void setHasUnreferenceableStorage(bool v) {
|
|
Bits.StructDecl.HasUnreferenceableStorage = v;
|
|
}
|
|
|
|
/// Does this struct represent a non-trivial (for the purpose of calls, as
|
|
/// defined by Itanium ABI) C++ record. A C++ record is considered non-trivial
|
|
/// for the purpose of calls if either its constructor, copy-constructor, or
|
|
/// destructor is non-trivial. As such, a C++ record with a non-trivial
|
|
/// copy-assignment operator but other trivial members is considered to be
|
|
/// trivial.
|
|
bool isCxxNonTrivial() const { return Bits.StructDecl.IsCxxNonTrivial; }
|
|
|
|
void setIsCxxNonTrivial(bool v) { Bits.StructDecl.IsCxxNonTrivial = v; }
|
|
|
|
bool isNonTrivialPtrAuth() const {
|
|
return Bits.StructDecl.IsNonTrivialPtrAuth;
|
|
}
|
|
|
|
void setHasNonTrivialPtrAuth(bool v) {
|
|
Bits.StructDecl.IsNonTrivialPtrAuth = v;
|
|
}
|
|
|
|
Type getTemplateInstantiationType() const { return TemplateInstantiationType; }
|
|
void setTemplateInstantiationType(Type t) { TemplateInstantiationType = t; }
|
|
};
|
|
|
|
/// This is the base type for AncestryOptions. Each flag describes possible
|
|
/// interesting kinds of superclasses that a class may have.
|
|
enum class AncestryFlags : uint8_t {
|
|
/// The class or one of its superclasses is @objc.
|
|
ObjC = (1<<0),
|
|
|
|
/// The class or one of its superclasses is @objcMembers.
|
|
ObjCMembers = (1<<1),
|
|
|
|
/// The class or one of its superclasses is generic.
|
|
Generic = (1<<2),
|
|
|
|
/// The class or one of its superclasses is resilient.
|
|
Resilient = (1<<3),
|
|
|
|
/// The class or one of its superclasses has resilient metadata and is in a
|
|
/// different resilience domain.
|
|
ResilientOther = (1<<4),
|
|
|
|
/// The class or one of its superclasses is imported from Clang.
|
|
ClangImported = (1<<5),
|
|
|
|
/// The class or one of its superclasses requires stored property initializers.
|
|
RequiresStoredPropertyInits = (1<<6),
|
|
|
|
/// The class uses the ObjC object model (reference counting,
|
|
/// isa encoding, etc.).
|
|
ObjCObjectModel = (1<<7),
|
|
};
|
|
|
|
/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
|
|
/// kinds of superclasses that a class may have.
|
|
using AncestryOptions = OptionSet<AncestryFlags>;
|
|
|
|
/// ClassDecl - This is the declaration of a class, for example:
|
|
///
|
|
/// class Complex { var R : Double, I : Double }
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Complex" in the above example).
|
|
class ClassDecl final : public NominalTypeDecl {
|
|
SourceLoc ClassLoc;
|
|
|
|
struct {
|
|
/// The superclass decl and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<ClassDecl *, 1, bool> SuperclassDecl;
|
|
|
|
/// The superclass type and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> SuperclassType;
|
|
} LazySemanticInfo;
|
|
|
|
std::optional<bool> getCachedInheritsSuperclassInitializers() const {
|
|
if (Bits.ClassDecl.ComputedInheritsSuperclassInits)
|
|
return Bits.ClassDecl.InheritsSuperclassInits;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<bool> getCachedHasMissingDesignatedInitializers() const {
|
|
if (!Bits.ClassDecl.ComputedHasMissingDesignatedInitializers) {
|
|
// Force loading all the members, which will add this attribute if any of
|
|
// members are determined to be missing while loading.
|
|
auto mutableThis = const_cast<ClassDecl *>(this);
|
|
(void)mutableThis->lookupDirect(DeclBaseName::createConstructor(),
|
|
getStartLoc());
|
|
}
|
|
|
|
if (Bits.ClassDecl.ComputedHasMissingDesignatedInitializers)
|
|
return Bits.ClassDecl.HasMissingDesignatedInitializers;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
void setHasMissingDesignatedInitializers(bool value) {
|
|
Bits.ClassDecl.HasMissingDesignatedInitializers = value;
|
|
Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = true;
|
|
}
|
|
|
|
/// Marks that this class inherits convenience initializers from its
|
|
/// superclass.
|
|
void setInheritsSuperclassInitializers(bool value) {
|
|
Bits.ClassDecl.InheritsSuperclassInits = value;
|
|
Bits.ClassDecl.ComputedInheritsSuperclassInits = true;
|
|
}
|
|
|
|
friend class SuperclassDeclRequest;
|
|
friend class SuperclassTypeRequest;
|
|
friend class ABIMembersRequest;
|
|
friend class HasMissingDesignatedInitializersRequest;
|
|
friend class InheritsSuperclassInitializersRequest;
|
|
|
|
public:
|
|
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
|
|
ArrayRef<InheritedEntry> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *DC,
|
|
bool isActor);
|
|
|
|
SourceLoc getStartLoc() const { return ClassLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(ClassLoc, getBraces().End);
|
|
}
|
|
|
|
/// Determine whether the member area of this class's metadata (which consists
|
|
/// of field offsets and vtable entries) is to be considered opaque by clients.
|
|
///
|
|
/// Note that even @_fixed_layout classes have resilient metadata if they are
|
|
/// in a resilient module.
|
|
bool hasResilientMetadata() const;
|
|
|
|
/// Determine whether this class has resilient metadata when accessed from the
|
|
/// given module and resilience expansion.
|
|
bool hasResilientMetadata(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// Determine whether this class has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }
|
|
|
|
/// Retrieve the superclass of this class, or null if there is no superclass.
|
|
Type getSuperclass() const;
|
|
|
|
/// Retrieve the ClassDecl for the superclass of this class, or null if there
|
|
/// is no superclass.
|
|
ClassDecl *getSuperclassDecl() const;
|
|
|
|
/// Check if this class is a superclass or equal to the given class.
|
|
bool isSuperclassOf(const ClassDecl *other) const;
|
|
|
|
/// Set the superclass of this class.
|
|
void setSuperclass(Type superclass);
|
|
|
|
/// Walk this class and all of the superclasses of this class, transitively,
|
|
/// invoking the callback function for each class.
|
|
///
|
|
/// \param fn The callback function that will be invoked for each superclass.
|
|
/// It can return \c Continue to continue the traversal. Returning
|
|
/// \c SkipChildren halts the search and returns \c false, while returning
|
|
/// \c Stop halts the search and returns \c true.
|
|
///
|
|
/// \returns \c true if \c fn returned \c Stop for any class, \c false
|
|
/// otherwise.
|
|
bool walkSuperclasses(
|
|
llvm::function_ref<TypeWalker::Action(ClassDecl *)> fn) const;
|
|
|
|
//// Whether this class requires all of its stored properties to
|
|
//// have initializers in the class definition.
|
|
bool requiresStoredPropertyInits() const {
|
|
return checkAncestry(AncestryFlags::RequiresStoredPropertyInits);
|
|
}
|
|
|
|
/// \see getForeignClassKind
|
|
enum class ForeignKind : uint8_t {
|
|
/// A normal Swift or Objective-C class.
|
|
Normal = 0,
|
|
/// An imported Core Foundation type. These are AnyObject-compatible but
|
|
/// do not have runtime metadata.
|
|
CFType,
|
|
/// An imported Objective-C type whose class and metaclass symbols are not
|
|
/// both available at link-time but can be accessed through the Objective-C
|
|
/// runtime.
|
|
RuntimeOnly
|
|
};
|
|
|
|
/// Whether this class is "foreign", meaning that it is implemented
|
|
/// by a runtime that Swift does not have first-class integration
|
|
/// with. This generally means that:
|
|
/// - class data is either abstracted or cannot be made to
|
|
/// fit with Swift's metatype schema, and/or
|
|
/// - there is no facility for subclassing or adding polymorphic
|
|
/// methods to the class.
|
|
///
|
|
/// We may find ourselves wanting to break this bit into more
|
|
/// precise chunks later.
|
|
ForeignKind getForeignClassKind() const {
|
|
return static_cast<ForeignKind>(Bits.ClassDecl.RawForeignKind);
|
|
}
|
|
void setForeignClassKind(ForeignKind kind) {
|
|
Bits.ClassDecl.RawForeignKind = static_cast<unsigned>(kind);
|
|
}
|
|
|
|
/// Returns true if this class is any kind of "foreign class".
|
|
///
|
|
/// \see getForeignClassKind
|
|
bool isForeign() const {
|
|
return getForeignClassKind() != ForeignKind::Normal ||
|
|
const_cast<ClassDecl *>(this)->isForeignReferenceType();
|
|
}
|
|
|
|
/// Whether the class is (known to be) a default actor.
|
|
bool isDefaultActor() const;
|
|
bool isDefaultActor(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// Whether the class is known to be a *root* default actor,
|
|
/// i.e. the first class in its hierarchy that is a default actor.
|
|
bool isRootDefaultActor() const;
|
|
bool isRootDefaultActor(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// It is a `distributed actor` with a custom executor.
|
|
bool isNonDefaultExplicitDistributedActor() const;
|
|
bool isNonDefaultExplicitDistributedActor(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// Whether the class was explicitly declared with the `actor` keyword.
|
|
bool isExplicitActor() const { return Bits.ClassDecl.IsActor; }
|
|
|
|
/// Whether the class was explicitly declared with the `distributed actor` keywords.
|
|
bool isExplicitDistributedActor() const {
|
|
return isExplicitActor() &&
|
|
getAttrs().hasAttribute<DistributedActorAttr>();
|
|
}
|
|
|
|
/// Get the closest-to-root superclass that's an actor class.
|
|
const ClassDecl *getRootActorClass() const;
|
|
|
|
/// Fetch this class's unownedExecutor property, if it has one.
|
|
const VarDecl *getUnownedExecutorProperty() const;
|
|
|
|
/// Is this the NSObject class type?
|
|
bool isNSObject() const;
|
|
|
|
/// Whether the class directly inherits from NSObject but should use
|
|
/// Swift's native object model.
|
|
bool isNativeNSObjectSubclass() const;
|
|
|
|
/// Whether the class uses the ObjC object model (reference counting,
|
|
/// allocation, etc.), the Swift model, or has no reference counting at all.
|
|
ReferenceCounting getObjectModel() const;
|
|
|
|
LayoutConstraintKind getLayoutConstraintKind() const {
|
|
if (getObjectModel() == ReferenceCounting::ObjC)
|
|
return LayoutConstraintKind::Class;
|
|
|
|
return LayoutConstraintKind::NativeClass;
|
|
}
|
|
|
|
/// Returns true if the class has designated initializers that are not listed
|
|
/// in its members.
|
|
///
|
|
/// This can occur, for example, if the class is an Objective-C class with
|
|
/// initializers that cannot be represented in Swift.
|
|
bool hasMissingDesignatedInitializers() const;
|
|
|
|
/// Returns true if the class has missing members that require vtable entries.
|
|
///
|
|
/// In this case, the class cannot be subclassed, because we cannot construct
|
|
/// the vtable for the subclass.
|
|
bool hasMissingVTableEntries() const;
|
|
|
|
void setHasMissingVTableEntries(bool newValue = true) {
|
|
Bits.ClassDecl.ComputedHasMissingVTableEntries = 1;
|
|
Bits.ClassDecl.HasMissingVTableEntries = newValue;
|
|
}
|
|
|
|
/// Returns true if this class cannot be used with weak or unowned
|
|
/// references.
|
|
///
|
|
/// Note that this is true if this class or any of its ancestor classes
|
|
/// are marked incompatible.
|
|
bool isIncompatibleWithWeakReferences() const;
|
|
|
|
void setIsIncompatibleWithWeakReferences(bool newValue = true) {
|
|
Bits.ClassDecl.IsIncompatibleWithWeakReferences = newValue;
|
|
}
|
|
|
|
/// Find a method of a class that overrides a given method.
|
|
/// Return nullptr, if no such method exists.
|
|
AbstractFunctionDecl *findOverridingDecl(
|
|
const AbstractFunctionDecl *method) const;
|
|
|
|
/// Find a method implementation which will be used when a given method
|
|
/// is invoked on an instance of this class. This implementation may stem
|
|
/// either from a class itself or its direct or indirect superclasses.
|
|
AbstractFunctionDecl *findImplementingMethod(
|
|
const AbstractFunctionDecl *method) const;
|
|
|
|
/// Retrieve the destructor for this class.
|
|
DestructorDecl *getDestructor() const;
|
|
|
|
/// Determine whether this class inherits the convenience initializers
|
|
/// from its superclass.
|
|
bool inheritsSuperclassInitializers() const;
|
|
|
|
/// Walks the class hierarchy starting from this class, checking various
|
|
/// conditions.
|
|
AncestryOptions checkAncestry() const;
|
|
|
|
/// Check if the class has ancestry of the given kind.
|
|
bool checkAncestry(AncestryFlags flag) const {
|
|
return checkAncestry().contains(flag);
|
|
}
|
|
|
|
/// The type of metaclass to use for a class.
|
|
enum class MetaclassKind : uint8_t {
|
|
ObjC,
|
|
SwiftStub,
|
|
};
|
|
|
|
/// Determine which sort of metaclass to use for this class
|
|
MetaclassKind getMetaclassKind() const;
|
|
|
|
/// Retrieve the name to use for this class when interoperating with
|
|
/// the Objective-C runtime.
|
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
|
|
|
/// Return the imported declaration(s) for the category with the given name; this
|
|
/// will either be a single imported \c ExtensionDecl, an imported
|
|
/// \c ClassDecl followed by zero or more imported \c ExtensionDecl s (if
|
|
/// \p name is empty; the extensions are for any class extensions), or empty
|
|
/// if the class was not imported from Objective-C or does not have a
|
|
/// category by that name.
|
|
llvm::TinyPtrVector<Decl *>
|
|
getImportedObjCCategory(Identifier name) const;
|
|
|
|
/// Return a map of category names to extensions with that category name,
|
|
/// whether imported or otherwise.
|
|
llvm::DenseMap<Identifier, llvm::TinyPtrVector<ExtensionDecl *>>
|
|
getObjCCategoryNameMap();
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Returns true if the decl uses the Objective-C generics model.
|
|
///
|
|
/// This is true of imported Objective-C classes.
|
|
bool isTypeErasedGenericClass() const {
|
|
return hasClangNode() && isGenericContext() && isObjC();
|
|
}
|
|
|
|
/// True if the class is known to be implemented in Swift.
|
|
bool hasKnownSwiftImplementation() const {
|
|
return !hasClangNode();
|
|
}
|
|
|
|
/// Used to determine if this class decl is a foreign reference type. I.e., a
|
|
/// non-reference-counted swift reference type that was imported from a C++
|
|
/// record.
|
|
bool isForeignReferenceType() const;
|
|
|
|
bool hasRefCountingAnnotations() const;
|
|
};
|
|
|
|
/// The set of known protocols for which derived conformances are supported.
|
|
enum class KnownDerivableProtocolKind : uint8_t {
|
|
RawRepresentable,
|
|
OptionSet,
|
|
CaseIterable,
|
|
Comparable,
|
|
Equatable,
|
|
Hashable,
|
|
BridgedNSError,
|
|
CodingKey,
|
|
Encodable,
|
|
Decodable,
|
|
AdditiveArithmetic,
|
|
Differentiable,
|
|
Identifiable,
|
|
Actor,
|
|
DistributedActor,
|
|
DistributedActorSystem,
|
|
};
|
|
|
|
using PrimaryAssociatedTypeName = std::pair<Identifier, SourceLoc>;
|
|
|
|
/// A wrapper for a dictionary that maps Obj-C protocol requirement selectors to
|
|
/// a list of function decls.
|
|
class ObjCRequirementMap {
|
|
public:
|
|
using FunctionList = TinyPtrVector<AbstractFunctionDecl *>;
|
|
|
|
private:
|
|
using MethodKey = std::pair<ObjCSelector, char>;
|
|
llvm::SmallDenseMap<MethodKey, FunctionList, 4> storage;
|
|
|
|
static MethodKey getObjCMethodKey(AbstractFunctionDecl *func);
|
|
|
|
public:
|
|
void addRequirement(AbstractFunctionDecl *requirement) {
|
|
storage[getObjCMethodKey(requirement)].push_back(requirement);
|
|
}
|
|
|
|
/// Retrieve the Objective-C requirements in this protocol that have the
|
|
/// given Objective-C method key.
|
|
FunctionList getRequirements(AbstractFunctionDecl *requirement) const {
|
|
auto key = getObjCMethodKey(requirement);
|
|
auto known = storage.find(key);
|
|
if (known == storage.end())
|
|
return {};
|
|
|
|
return known->second;
|
|
}
|
|
};
|
|
|
|
/// ProtocolDecl - A declaration of a protocol, for example:
|
|
///
|
|
/// protocol Drawable {
|
|
/// func draw()
|
|
/// }
|
|
///
|
|
/// Every protocol has an implicitly-created 'Self' generic parameter that
|
|
/// stands for a type that conforms to the protocol. For example,
|
|
///
|
|
/// protocol Clonable {
|
|
/// func clone() -> Self
|
|
/// }
|
|
///
|
|
class ProtocolDecl final : public NominalTypeDecl {
|
|
SourceLoc ProtocolLoc;
|
|
|
|
ArrayRef<PrimaryAssociatedTypeName> PrimaryAssociatedTypeNames;
|
|
ArrayRef<ProtocolDecl *> InheritedProtocols;
|
|
ArrayRef<ProtocolDecl *> AllInheritedProtocols;
|
|
ArrayRef<AssociatedTypeDecl *> AssociatedTypes;
|
|
ArrayRef<ValueDecl *> ProtocolRequirements;
|
|
|
|
struct {
|
|
/// The superclass decl and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<ClassDecl *, 1, bool> SuperclassDecl;
|
|
} LazySemanticInfo;
|
|
|
|
/// The generic signature representing exactly the new requirements introduced
|
|
/// by this protocol.
|
|
RequirementSignature RequirementSig;
|
|
|
|
/// Returns the cached result of \c requiresClass or \c None if it hasn't yet
|
|
/// been computed.
|
|
std::optional<bool> getCachedRequiresClass() const {
|
|
if (Bits.ProtocolDecl.RequiresClassValid)
|
|
return Bits.ProtocolDecl.RequiresClass;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Caches the result of \c requiresClass
|
|
void setCachedRequiresClass(bool requiresClass) {
|
|
Bits.ProtocolDecl.RequiresClassValid = true;
|
|
Bits.ProtocolDecl.RequiresClass = requiresClass;
|
|
}
|
|
|
|
/// Returns the cached result of \c existentialConformsToSelf or \c None if it
|
|
/// hasn't yet been computed.
|
|
std::optional<bool> getCachedExistentialConformsToSelf() const {
|
|
if (Bits.ProtocolDecl.ExistentialConformsToSelfValid)
|
|
return Bits.ProtocolDecl.ExistentialConformsToSelf;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Caches the result of \c existentialConformsToSelf
|
|
void setCachedExistentialConformsToSelf(bool result) {
|
|
Bits.ProtocolDecl.ExistentialConformsToSelfValid = true;
|
|
Bits.ProtocolDecl.ExistentialConformsToSelf = result;
|
|
}
|
|
|
|
/// Returns the cached result of \c hasSelfOrAssociatedTypeRequirements or
|
|
/// \c None if it hasn't yet been computed.
|
|
std::optional<bool> getCachedHasSelfOrAssociatedTypeRequirements() {
|
|
if (Bits.ProtocolDecl.HasSelfOrAssociatedTypeRequirementsValid)
|
|
return static_cast<bool>(Bits.ProtocolDecl.HasSelfOrAssociatedTypeRequirements);
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Caches the result of \c hasSelfOrAssociatedTypeRequirements
|
|
void setCachedHasSelfOrAssociatedTypeRequirements(bool value) {
|
|
Bits.ProtocolDecl.HasSelfOrAssociatedTypeRequirementsValid = true;
|
|
Bits.ProtocolDecl.HasSelfOrAssociatedTypeRequirements = value;
|
|
}
|
|
|
|
bool hasLazyRequirementSignature() const {
|
|
return Bits.ProtocolDecl.HasLazyRequirementSignature;
|
|
}
|
|
|
|
bool hasLazyPrimaryAssociatedTypes() const {
|
|
return Bits.ProtocolDecl.HasLazyPrimaryAssociatedTypes;
|
|
}
|
|
|
|
friend class SuperclassDeclRequest;
|
|
friend class SuperclassTypeRequest;
|
|
friend class StructuralRequirementsRequest;
|
|
friend class TypeAliasRequirementsRequest;
|
|
friend class ProtocolDependenciesRequest;
|
|
friend class RequirementSignatureRequest;
|
|
friend class ProtocolRequiresClassRequest;
|
|
friend class ExistentialConformsToSelfRequest;
|
|
friend class HasSelfOrAssociatedTypeRequirementsRequest;
|
|
friend class InheritedProtocolsRequest;
|
|
friend class AllInheritedProtocolsRequest;
|
|
friend class PrimaryAssociatedTypesRequest;
|
|
friend class ProtocolRequirementsRequest;
|
|
|
|
public:
|
|
ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc,
|
|
Identifier Name,
|
|
ArrayRef<PrimaryAssociatedTypeName> PrimaryAssociatedTypeNames,
|
|
ArrayRef<InheritedEntry> Inherited,
|
|
TrailingWhereClause *TrailingWhere);
|
|
|
|
using Decl::getASTContext;
|
|
|
|
/// Retrieve the set of protocols inherited from this protocol.
|
|
ArrayRef<ProtocolDecl *> getInheritedProtocols() const;
|
|
|
|
/// Retrieve the transitive closure of the inherited protocols, not including
|
|
/// this protocol itself.
|
|
ArrayRef<ProtocolDecl *> getAllInheritedProtocols() const;
|
|
|
|
/// Determine whether this protocol has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }
|
|
|
|
/// Retrieve the ClassDecl for the superclass of this protocol, or null if there
|
|
/// is no superclass.
|
|
ClassDecl *getSuperclassDecl() const;
|
|
|
|
/// Retrieve the set of AssociatedTypeDecl members of this protocol; this
|
|
/// saves loading the set of members in cases where there's no possibility of
|
|
/// a protocol having nested types (ObjC protocols).
|
|
ArrayRef<AssociatedTypeDecl *> getAssociatedTypeMembers() const;
|
|
|
|
/// Returns the list of primary associated type names. These are the associated
|
|
/// types that is parametrized with same-type requirements in a
|
|
/// parametrized protocol type of the form SomeProtocol<Arg1, Arg2...>.
|
|
ArrayRef<PrimaryAssociatedTypeName> getPrimaryAssociatedTypeNames() const {
|
|
return PrimaryAssociatedTypeNames;
|
|
}
|
|
|
|
/// Returns the list of primary associated types. These are the associated
|
|
/// types that is parametrized with same-type requirements in a
|
|
/// parametrized protocol type of the form SomeProtocol<Arg1, Arg2...>.
|
|
ArrayRef<AssociatedTypeDecl *> getPrimaryAssociatedTypes() const;
|
|
|
|
/// Returns the list of all requirements (associated type and value)
|
|
/// associated with this protocol.
|
|
ArrayRef<ValueDecl *> getProtocolRequirements() const;
|
|
|
|
/// Returns a protocol requirement with the given name, or nullptr if the
|
|
/// name has multiple overloads, or no overloads at all.
|
|
ValueDecl *getSingleRequirement(DeclName name) const;
|
|
|
|
/// Returns an associated type with the given name, or nullptr if one does
|
|
/// not exist.
|
|
AssociatedTypeDecl *getAssociatedType(Identifier name) const;
|
|
|
|
/// Returns the existential type for this protocol.
|
|
Type getDeclaredExistentialType() const {
|
|
return ExistentialType::get(getDeclaredInterfaceType());
|
|
}
|
|
|
|
/// Walk this protocol and all of the protocols inherited by this protocol,
|
|
/// transitively, invoking the callback function for each protocol.
|
|
///
|
|
/// \param fn The callback function that will be invoked for each inherited
|
|
/// protocol. It can return \c Continue to continue the traversal,
|
|
/// \c SkipChildren to avoid visiting the children of the given protocol
|
|
/// but continue the search, and \c Stop to halt the search.
|
|
///
|
|
/// \returns \c true if \c fn returned \c Stop for any protocol, \c false
|
|
/// otherwise.
|
|
bool walkInheritedProtocols(
|
|
llvm::function_ref<TypeWalker::Action(ProtocolDecl *)> fn) const;
|
|
|
|
/// Determine whether this protocol inherits from the given ("super")
|
|
/// protocol.
|
|
bool inheritsFrom(const ProtocolDecl *Super) const;
|
|
|
|
SourceLoc getStartLoc() const { return ProtocolLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(ProtocolLoc, getBraces().End);
|
|
}
|
|
|
|
/// True if this protocol can only be conformed to by class types.
|
|
bool requiresClass() const;
|
|
|
|
/// Determine whether an existential conforming to this protocol can be
|
|
/// matched with a generic type parameter constrained to this protocol.
|
|
/// This is only permitted if there is nothing "non-trivial" that we
|
|
/// can do with the metatype, which means the protocol must not have
|
|
/// any static methods and must be declared @objc.
|
|
bool existentialConformsToSelf() const;
|
|
|
|
/// Does this protocol require a self-conformance witness table?
|
|
bool requiresSelfConformanceWitnessTable() const;
|
|
|
|
/// Determine whether this protocol has `Self` or associated type
|
|
/// requirements.
|
|
///
|
|
/// This is true if one of the following conditions is met for this protocol
|
|
/// or an inherited protocol:
|
|
/// - The protocol has an associated type requirement.
|
|
/// - `Self` appears in non-covariant position in the type signature of a
|
|
/// value requirement.
|
|
bool hasSelfOrAssociatedTypeRequirements() const;
|
|
|
|
/// Returns a list of protocol requirements that must be assessed to
|
|
/// determine a concrete's conformance effect polymorphism kind.
|
|
PolymorphicEffectRequirementList getPolymorphicEffectRequirements(
|
|
EffectKind kind) const;
|
|
bool hasPolymorphicEffect(EffectKind kind) const;
|
|
|
|
/// Determine whether this is a "marker" protocol, meaning that is indicates
|
|
/// semantics but has no corresponding witness table.
|
|
bool isMarkerProtocol() const;
|
|
|
|
/// Determine if this is an invertible protocol and return its kind,
|
|
/// i.e., for a protocol P, returns the kind if inverse constraint ~P exists.
|
|
std::optional<InvertibleProtocolKind> getInvertibleProtocolKind() const;
|
|
|
|
/// Returns a dictionary that maps Obj-C protocol requirement selectors to a
|
|
/// list of function decls.
|
|
ObjCRequirementMap getObjCRequiremenMap() const;
|
|
|
|
private:
|
|
void computeKnownProtocolKind() const;
|
|
|
|
bool areInheritedProtocolsValid() const {
|
|
return Bits.ProtocolDecl.InheritedProtocolsValid;
|
|
}
|
|
void setInheritedProtocolsValid() {
|
|
Bits.ProtocolDecl.InheritedProtocolsValid = true;
|
|
}
|
|
|
|
bool areAllInheritedProtocolsValid() const {
|
|
return Bits.ProtocolDecl.AllInheritedProtocolsValid;
|
|
}
|
|
void setAllInheritedProtocolsValid() {
|
|
Bits.ProtocolDecl.AllInheritedProtocolsValid = true;
|
|
}
|
|
|
|
bool areProtocolRequirementsValid() const {
|
|
return Bits.ProtocolDecl.ProtocolRequirementsValid;
|
|
}
|
|
void setProtocolRequirementsValid() {
|
|
Bits.ProtocolDecl.ProtocolRequirementsValid = true;
|
|
}
|
|
|
|
public:
|
|
/// If this is known to be a compiler-known protocol, returns the kind.
|
|
/// Otherwise returns None.
|
|
std::optional<KnownProtocolKind> getKnownProtocolKind() const {
|
|
if (Bits.ProtocolDecl.KnownProtocol == 0)
|
|
computeKnownProtocolKind();
|
|
|
|
if (Bits.ProtocolDecl.KnownProtocol == 1)
|
|
return std::nullopt;
|
|
|
|
return static_cast<KnownProtocolKind>(Bits.ProtocolDecl.KnownProtocol - 2);
|
|
}
|
|
|
|
std::optional<KnownDerivableProtocolKind>
|
|
getKnownDerivableProtocolKind() const;
|
|
|
|
/// Check whether this protocol is of a specific, known protocol kind.
|
|
bool isSpecificProtocol(KnownProtocolKind kind) const {
|
|
if (auto knownKind = getKnownProtocolKind())
|
|
return *knownKind == kind;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// Whether this protocol has a circular reference in its list of inherited
|
|
/// protocols.
|
|
bool hasCircularInheritedProtocols() const;
|
|
|
|
/// Returns true if the protocol has requirements that are not listed in its
|
|
/// members.
|
|
///
|
|
/// This can occur, for example, if the protocol is an Objective-C protocol
|
|
/// with requirements that cannot be represented in Swift.
|
|
bool hasMissingRequirements() const {
|
|
(void)getMembers();
|
|
return Bits.ProtocolDecl.HasMissingRequirements;
|
|
}
|
|
|
|
void setHasMissingRequirements(bool newValue) {
|
|
Bits.ProtocolDecl.HasMissingRequirements = newValue;
|
|
}
|
|
|
|
/// Returns the default type witness for an associated type, or a null
|
|
/// type if there is no default.
|
|
Type getDefaultTypeWitness(AssociatedTypeDecl *assocType) const;
|
|
|
|
/// Set the default type witness for an associated type.
|
|
void setDefaultTypeWitness(AssociatedTypeDecl *assocType, Type witness);
|
|
|
|
/// Returns the default witness for a requirement, or nullptr if there is
|
|
/// no default.
|
|
Witness getDefaultWitness(ValueDecl *requirement) const;
|
|
|
|
/// Record the default witness for a requirement.
|
|
void setDefaultWitness(ValueDecl *requirement, Witness witness);
|
|
|
|
/// Returns the default associated conformance witness for an associated
|
|
/// type, or \c None if there is no default.
|
|
ProtocolConformanceRef
|
|
getDefaultAssociatedConformanceWitness(CanType association,
|
|
ProtocolDecl *requirement) const;
|
|
|
|
/// Set the default associated conformance witness for the given
|
|
/// associated conformance.
|
|
void setDefaultAssociatedConformanceWitness(
|
|
CanType association,
|
|
ProtocolDecl *requirement,
|
|
ProtocolConformanceRef conformance);
|
|
|
|
/// Retrieve the name to use for this protocol when interoperating
|
|
/// with the Objective-C runtime.
|
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
|
|
|
/// Retrieve the original requirements written in source, as structural types.
|
|
///
|
|
/// The requirement machine builds the requirement signature from structural
|
|
/// requirements. Almost everywhere else should use getRequirementSignature()
|
|
/// instead.
|
|
ArrayRef<StructuralRequirement> getStructuralRequirements() const;
|
|
|
|
/// Retrieve same-type requirements implied by protocol typealiases with the
|
|
/// same name as associated types, and diagnose cases that are better expressed
|
|
/// via a 'where' clause.
|
|
ArrayRef<Requirement> getTypeAliasRequirements() const;
|
|
|
|
/// Get the list of protocols appearing on the right hand side of conformance
|
|
/// requirements. Computed from the structural requirements, above.
|
|
ArrayRef<ProtocolDecl *> getProtocolDependencies() const;
|
|
|
|
/// Retrieve the requirements that describe this protocol from the point of
|
|
/// view of the generic system; see RequirementSignature.h for details.
|
|
RequirementSignature getRequirementSignature() const;
|
|
|
|
/// Is the requirement signature currently being computed?
|
|
bool isComputingRequirementSignature() const;
|
|
|
|
/// Has the requirement signature been computed yet?
|
|
bool isRequirementSignatureComputed() const {
|
|
return Bits.ProtocolDecl.HasRequirementSignature;
|
|
}
|
|
|
|
void setRequirementSignature(RequirementSignature requirementSig);
|
|
|
|
void setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
|
|
uint64_t requirementSignatureData);
|
|
|
|
void setLazyAssociatedTypeMembers(LazyMemberLoader *lazyLoader,
|
|
uint64_t associatedTypesData);
|
|
|
|
void setLazyPrimaryAssociatedTypeMembers(LazyMemberLoader *lazyLoader,
|
|
uint64_t associatedTypesData);
|
|
|
|
public:
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
};
|
|
|
|
/// This is the special singleton Builtin.TheTupleType. It is not directly
|
|
/// visible in the source language, but we use it to attach extensions
|
|
/// and conformances for tuple types.
|
|
///
|
|
/// - The declared interface type is the special TheTupleType singleton.
|
|
/// - The generic parameter list has one pack generic parameter, <each Element>
|
|
/// - The generic signature has no requirements, <each Element>
|
|
/// - The self interface type is the tuple type containing a single pack
|
|
/// expansion, (repeat each Element).
|
|
class BuiltinTupleDecl final : public NominalTypeDecl {
|
|
public:
|
|
BuiltinTupleDecl(Identifier Name, DeclContext *Parent);
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange();
|
|
}
|
|
|
|
TupleType *getTupleSelfType(const ExtensionDecl *owner) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::BuiltinTuple;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::BuiltinTuple;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::BuiltinTuple;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
};
|
|
|
|
/// Describes whether a particular storage declaration is mutable.
|
|
enum class StorageMutability {
|
|
/// The storage is immutable, meaning that it can neither be assigned
|
|
/// to nor passed inout.
|
|
Immutable,
|
|
|
|
/// The storage is mutable, meaning that it can be assigned and pased
|
|
/// inout.
|
|
Mutable,
|
|
|
|
/// The storage is immutable, but can be asigned for the purposes of
|
|
/// initialization.
|
|
Initializable
|
|
};
|
|
|
|
/// AbstractStorageDecl - This is the common superclass for VarDecl and
|
|
/// SubscriptDecl, representing potentially settable memory locations.
|
|
class AbstractStorageDecl : public ValueDecl {
|
|
friend class HasStorageRequest;
|
|
friend class SetterAccessLevelRequest;
|
|
friend class IsGetterMutatingRequest;
|
|
friend class IsSetterMutatingRequest;
|
|
friend class OpaqueReadOwnershipRequest;
|
|
friend class StorageImplInfoRequest;
|
|
friend class RequiresOpaqueAccessorsRequest;
|
|
friend class RequiresOpaqueModifyCoroutineRequest;
|
|
friend class SynthesizeAccessorRequest;
|
|
|
|
public:
|
|
static const size_t MaxNumAccessors = 255;
|
|
private:
|
|
/// A record of the accessors for the declaration.
|
|
class alignas(1 << 3) AccessorRecord final :
|
|
private llvm::TrailingObjects<AccessorRecord, AccessorDecl*> {
|
|
friend TrailingObjects;
|
|
|
|
using AccessorIndex = uint8_t;
|
|
static const AccessorIndex InvalidIndex = 0;
|
|
|
|
/// The range of the braces around the accessor clause.
|
|
SourceRange Braces;
|
|
|
|
/// The number of accessors currently stored in this record.
|
|
AccessorIndex NumAccessors;
|
|
|
|
/// The storage capacity of this record for accessors. Always includes
|
|
/// enough space for adding opaque accessors to the record, which are the
|
|
/// only accessors that should ever be added retroactively; hence this
|
|
/// field is only here for the purposes of safety checks.
|
|
AccessorIndex AccessorsCapacity;
|
|
|
|
/// Either 0, meaning there is no registered accessor of the given kind,
|
|
/// or the index+1 of the accessor in the accessors array.
|
|
AccessorIndex AccessorIndices[NumAccessorKinds];
|
|
|
|
AccessorRecord(SourceRange braces,
|
|
ArrayRef<AccessorDecl*> accessors,
|
|
AccessorIndex accessorsCapacity);
|
|
public:
|
|
static AccessorRecord *create(ASTContext &ctx, SourceRange braces,
|
|
ArrayRef<AccessorDecl*> accessors);
|
|
|
|
SourceRange getBracesRange() const { return Braces; }
|
|
|
|
inline AccessorDecl *getAccessor(AccessorKind kind) const;
|
|
|
|
ArrayRef<AccessorDecl *> getAllAccessors() const {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
void addOpaqueAccessor(AccessorDecl *accessor);
|
|
|
|
void removeAccessor(AccessorDecl *accessor);
|
|
|
|
private:
|
|
MutableArrayRef<AccessorDecl *> getAccessorsBuffer() {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
bool registerAccessor(AccessorDecl *accessor, AccessorIndex index);
|
|
};
|
|
|
|
llvm::PointerIntPair<AccessorRecord*, 3, OptionalEnum<AccessLevel>> Accessors;
|
|
|
|
struct {
|
|
unsigned HasStorageComputed : 1;
|
|
unsigned HasStorage : 1;
|
|
unsigned IsGetterMutatingComputed : 1;
|
|
unsigned IsGetterMutating : 1;
|
|
unsigned IsSetterMutatingComputed : 1;
|
|
unsigned IsSetterMutating : 1;
|
|
unsigned OpaqueReadOwnershipComputed : 1;
|
|
unsigned OpaqueReadOwnership : 2;
|
|
unsigned ImplInfoComputed : 1;
|
|
unsigned RequiresOpaqueAccessorsComputed : 1;
|
|
unsigned RequiresOpaqueAccessors : 1;
|
|
unsigned RequiresOpaqueModifyCoroutineComputed : 1;
|
|
unsigned RequiresOpaqueModifyCoroutine : 1;
|
|
unsigned RequiresOpaqueModify2CoroutineComputed : 1;
|
|
unsigned RequiresOpaqueModify2Coroutine : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
/// The implementation info for the accessors.
|
|
StorageImplInfo ImplInfo;
|
|
|
|
/// Add a synthesized accessor.
|
|
void setSynthesizedAccessor(AccessorKind kind, AccessorDecl *getter);
|
|
|
|
protected:
|
|
AbstractStorageDecl(DeclKind Kind, bool IsStatic, DeclContext *DC,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
StorageIsMutable_t supportsMutation)
|
|
: ValueDecl(Kind, DC, Name, NameLoc),
|
|
ImplInfo(StorageImplInfo::getSimpleStored(supportsMutation)) {
|
|
Bits.AbstractStorageDecl.IsStatic = IsStatic;
|
|
}
|
|
|
|
public:
|
|
|
|
/// Should this declaration be treated as if annotated with transparent
|
|
/// attribute.
|
|
bool isTransparent() const;
|
|
|
|
/// Is this a type ('static') variable?
|
|
bool isStatic() const {
|
|
return Bits.AbstractStorageDecl.IsStatic;
|
|
}
|
|
void setStatic(bool IsStatic) {
|
|
Bits.AbstractStorageDecl.IsStatic = IsStatic;
|
|
}
|
|
bool isCompileTimeLiteral() const;
|
|
bool isConstValue() const;
|
|
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
|
|
/// Return the interface type of the stored value.
|
|
Type getValueInterfaceType() const;
|
|
|
|
/// Retrieve the source range of the variable type, or an invalid range if the
|
|
/// variable's type is not explicitly written in the source.
|
|
///
|
|
/// Only for use in diagnostics. It is not always possible to always
|
|
/// precisely point to the variable type because of type aliases.
|
|
SourceRange getTypeSourceRangeForDiagnostics() const;
|
|
|
|
/// Determine how this storage is implemented.
|
|
StorageImplInfo getImplInfo() const;
|
|
|
|
/// Overwrite the registered implementation-info. This should be
|
|
/// used carefully.
|
|
void setImplInfo(StorageImplInfo implInfo);
|
|
|
|
/// Cache the implementation-info, for use by the request-evaluator.
|
|
void cacheImplInfo(StorageImplInfo implInfo);
|
|
|
|
ReadImplKind getReadImpl() const {
|
|
return getImplInfo().getReadImpl();
|
|
}
|
|
WriteImplKind getWriteImpl() const {
|
|
return getImplInfo().getWriteImpl();
|
|
}
|
|
ReadWriteImplKind getReadWriteImpl() const {
|
|
return getImplInfo().getReadWriteImpl();
|
|
}
|
|
|
|
/// Return true if this is a VarDecl that has storage associated with
|
|
/// it.
|
|
bool hasStorage() const;
|
|
|
|
/// Return true if this is a VarDecl that has init accessor associated
|
|
/// with it.
|
|
bool hasInitAccessor() const;
|
|
|
|
/// Return true if this is a property that either has storage
|
|
/// or init accessor associated with it.
|
|
bool supportsInitialization() const {
|
|
return hasStorage() || hasInitAccessor();
|
|
}
|
|
|
|
/// Return true if this storage has the basic accessors/capability
|
|
/// to be mutated. This is generally constant after the accessors are
|
|
/// installed by the parser/importer/whatever.
|
|
///
|
|
/// Note that this is different from the mutability of the declaration
|
|
/// in the user language: sometimes we can assign to declarations that
|
|
/// don't support mutation (e.g. to initialize them), and sometimes we
|
|
/// can't mutate things that do support mutation (e.g. because their
|
|
/// setter is private).
|
|
StorageIsMutable_t supportsMutation() const {
|
|
return getImplInfo().supportsMutation();
|
|
}
|
|
|
|
/// Determine whether references to this storage declaration may appear
|
|
/// on the left-hand side of an assignment, as the operand of a
|
|
/// `&` or 'inout' operator, or as a component in a writable key path.
|
|
bool isSettable(const DeclContext *useDC) const {
|
|
switch (mutability(useDC)) {
|
|
case StorageMutability::Immutable:
|
|
return false;
|
|
case StorageMutability::Mutable:
|
|
case StorageMutability::Initializable:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// Determine the mutability of this storage declaration when
|
|
/// accessed from a given declaration context.
|
|
StorageMutability mutability(
|
|
const DeclContext *useDC,
|
|
std::optional<const DeclRefExpr *> base = std::nullopt) const;
|
|
|
|
/// Determine the mutability of this storage declaration when
|
|
/// accessed from a given declaration context in Swift.
|
|
///
|
|
/// This method differs only from 'mutability()' in its handling of
|
|
/// 'optional' storage requirements, which lack support for direct
|
|
/// writes in Swift.
|
|
StorageMutability mutabilityInSwift(
|
|
const DeclContext *useDC,
|
|
std::optional<const DeclRefExpr *> base = std::nullopt) const;
|
|
|
|
/// Determine whether references to this storage declaration in Swift may
|
|
/// appear on the left-hand side of an assignment, as the operand of a
|
|
/// `&` or 'inout' operator, or as a component in a writable key path.
|
|
///
|
|
/// This method is equivalent to \c isSettable with the exception of
|
|
/// 'optional' storage requirements, which lack support for direct writes
|
|
/// in Swift.
|
|
bool isSettableInSwift(const DeclContext *useDC) const {
|
|
switch (mutabilityInSwift(useDC)) {
|
|
case StorageMutability::Immutable:
|
|
return false;
|
|
case StorageMutability::Mutable:
|
|
case StorageMutability::Initializable:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// Does this storage declaration have explicitly-defined accessors
|
|
/// written in the source?
|
|
bool hasParsedAccessors() const;
|
|
|
|
/// Return the ownership of values opaquely read from this storage.
|
|
OpaqueReadOwnership getOpaqueReadOwnership() const;
|
|
void setOpaqueReadOwnership(OpaqueReadOwnership ownership) {
|
|
LazySemanticInfo.OpaqueReadOwnership = unsigned(ownership);
|
|
LazySemanticInfo.OpaqueReadOwnershipComputed = true;
|
|
}
|
|
|
|
/// Return true if reading this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isGetterMutating() const;
|
|
void setIsGetterMutating(bool isMutating) {
|
|
LazySemanticInfo.IsGetterMutating = isMutating;
|
|
LazySemanticInfo.IsGetterMutatingComputed = true;
|
|
}
|
|
|
|
/// Return true if modifying this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isSetterMutating() const;
|
|
void setIsSetterMutating(bool isMutating) {
|
|
LazySemanticInfo.IsSetterMutating = isMutating;
|
|
LazySemanticInfo.IsSetterMutatingComputed = true;
|
|
}
|
|
|
|
AccessorDecl *getAccessor(AccessorKind kind) const {
|
|
if (auto info = Accessors.getPointer())
|
|
return info->getAccessor(kind);
|
|
return nullptr;
|
|
}
|
|
|
|
ArrayRef<AccessorDecl*> getAllAccessors() const {
|
|
if (const auto *info = Accessors.getPointer())
|
|
return info->getAllAccessors();
|
|
return {};
|
|
}
|
|
|
|
void removeAccessor(AccessorDecl *accessor) {
|
|
if (auto *info = Accessors.getPointer())
|
|
return info->removeAccessor(accessor);
|
|
}
|
|
|
|
/// This is the primary mechanism by which we can easily determine whether
|
|
/// this storage decl has any effects.
|
|
///
|
|
/// \returns the getter decl iff this decl has only one accessor that is
|
|
/// a 'get' with an effect (i.e., 'async', 'throws', or both).
|
|
/// Otherwise returns nullptr.
|
|
AccessorDecl *getEffectfulGetAccessor() const;
|
|
|
|
/// Performs a "limit check" on an effect possibly exhibited by this storage
|
|
/// decl with respect to some other storage decl that serves as the "limit."
|
|
/// This check says that \c this is less effectful than \c other if
|
|
/// \c this either does not exhibit the effect, or if it does, then \c other
|
|
/// also exhibits the effect. Thus, it is conceptually equivalent to
|
|
/// a less-than-or-equal (≤) check like so:
|
|
///
|
|
/// \verbatim
|
|
///
|
|
/// this->hasEffect(E) ≤ other->hasEffect(E)
|
|
///
|
|
/// \endverbatim
|
|
///
|
|
/// \param kind the single effect we are performing a check for.
|
|
///
|
|
/// \returns true iff \c this decl either does not exhibit the effect,
|
|
/// or \c other also exhibits the effect.
|
|
bool isLessEffectfulThan(AbstractStorageDecl const* other,
|
|
EffectKind kind) const;
|
|
|
|
/// Return an accessor that this storage is expected to have, synthesizing
|
|
/// one if necessary. Note that will always synthesize one, even if the
|
|
/// accessor is not part of the expected opaque set for the storage, so use
|
|
/// with caution.
|
|
AccessorDecl *getSynthesizedAccessor(AccessorKind kind) const;
|
|
|
|
/// Return an accessor part of the set of opaque accessors dictated by the
|
|
/// requirements of the ABI.
|
|
///
|
|
/// This will synthesize the accessor if one is required but not specified
|
|
/// in source; for example, most of the time a mutable property is required
|
|
/// to have a 'modify' accessor, but if the property was only written with
|
|
/// 'get' and 'set' accessors, 'modify' will be synthesized to call 'get'
|
|
/// followed by 'set'.
|
|
///
|
|
/// If the accessor is not needed for ABI reasons, this returns nullptr.
|
|
/// To ensure an accessor is always returned, use getSynthesizedAccessor().
|
|
AccessorDecl *getOpaqueAccessor(AccessorKind kind) const;
|
|
|
|
/// Collect all opaque accessors.
|
|
ArrayRef<AccessorDecl*>
|
|
getOpaqueAccessors(llvm::SmallVectorImpl<AccessorDecl*> &scratch) const;
|
|
|
|
/// Return an accessor that was written in source. Returns null if the
|
|
/// accessor was not explicitly defined by the user.
|
|
AccessorDecl *getParsedAccessor(AccessorKind kind) const;
|
|
|
|
/// Visit all parsed accessors.
|
|
void visitParsedAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
/// Visit all opaque accessor kinds.
|
|
void visitExpectedOpaqueAccessors(
|
|
llvm::function_ref<void (AccessorKind)>) const;
|
|
|
|
/// Visit all opaque accessors.
|
|
void visitOpaqueAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
/// Visit all eagerly emitted accessors.
|
|
///
|
|
/// This is the union of the parsed and opaque sets.
|
|
void visitEmittedAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
void setAccessors(SourceLoc lbraceLoc, ArrayRef<AccessorDecl*> accessors,
|
|
SourceLoc rbraceLoc);
|
|
|
|
/// Add a setter to an existing Computed var.
|
|
///
|
|
/// This should only be used by the ClangImporter.
|
|
void setComputedSetter(AccessorDecl *Set);
|
|
|
|
/// Does this storage require opaque accessors of any kind?
|
|
bool requiresOpaqueAccessors() const;
|
|
|
|
/// Does this storage require an opaque accessor of the given kind?
|
|
bool requiresOpaqueAccessor(AccessorKind kind) const;
|
|
|
|
/// Does this storage require a 'get' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueGetter() const {
|
|
return getOpaqueReadOwnership() != OpaqueReadOwnership::Borrowed;
|
|
}
|
|
|
|
/// Does this storage require a '_read' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueReadCoroutine() const;
|
|
|
|
/// Does this storage require a 'read' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueRead2Coroutine() const;
|
|
|
|
/// Does this storage require a 'set' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueSetter() const { return supportsMutation(); }
|
|
|
|
/// Does this storage require a '_modify' accessor in its opaque-accessors
|
|
/// set?
|
|
bool requiresOpaqueModifyCoroutine() const;
|
|
|
|
/// Does this storage require a 'modify' accessor in its opaque-accessors
|
|
/// set?
|
|
bool requiresOpaqueModify2Coroutine() const;
|
|
|
|
/// Given that CoroutineAccessors is enabled, is _read/_modify required for
|
|
/// ABI stability?
|
|
bool requiresCorrespondingUnderscoredCoroutineAccessor(
|
|
AccessorKind kind, AccessorDecl const *decl = nullptr) const;
|
|
|
|
/// Does this storage have any explicit observers (willSet or didSet) attached
|
|
/// to it?
|
|
bool hasObservers() const {
|
|
return getParsedAccessor(AccessorKind::WillSet) ||
|
|
getParsedAccessor(AccessorKind::DidSet);
|
|
}
|
|
|
|
SourceRange getBracesRange() const {
|
|
if (auto info = Accessors.getPointer())
|
|
return info->getBracesRange();
|
|
return SourceRange();
|
|
}
|
|
|
|
AccessLevel getSetterFormalAccess() const;
|
|
|
|
AccessScope
|
|
getSetterFormalAccessScope(const DeclContext *useDC = nullptr,
|
|
bool treatUsableFromInlineAsPublic = false) const;
|
|
|
|
void setSetterAccess(AccessLevel accessLevel) {
|
|
assert(!Accessors.getInt().hasValue());
|
|
overwriteSetterAccess(accessLevel);
|
|
}
|
|
|
|
void overwriteSetterAccess(AccessLevel accessLevel);
|
|
|
|
/// Given that this is an Objective-C property or subscript declaration,
|
|
/// produce its getter selector.
|
|
ObjCSelector
|
|
getObjCGetterSelector(Identifier preferredName = Identifier()) const;
|
|
|
|
/// Given that this is an Objective-C property or subscript declaration,
|
|
/// produce its setter selector.
|
|
ObjCSelector
|
|
getObjCSetterSelector(Identifier preferredName = Identifier()) const;
|
|
|
|
AbstractStorageDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AbstractStorageDecl>(ValueDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Returns the location of 'override' keyword, if any.
|
|
SourceLoc getOverrideLoc() const;
|
|
|
|
/// Returns true if this declaration has a setter accessible from the given
|
|
/// context.
|
|
///
|
|
/// If \p DC is null, returns true only if the setter is public.
|
|
///
|
|
/// See \c isAccessibleFrom for a discussion of the \p forConformance
|
|
/// parameter.
|
|
bool isSetterAccessibleFrom(const DeclContext *DC,
|
|
bool forConformance=false) const;
|
|
|
|
/// Determine how this storage declaration should actually be accessed.
|
|
AccessStrategy getAccessStrategy(
|
|
AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module,
|
|
ResilienceExpansion expansion,
|
|
std::optional<std::pair<SourceRange, const DeclContext *>> location,
|
|
bool useOldABI) const;
|
|
|
|
/// Whether access is via physical storage.
|
|
bool isAccessedViaPhysicalStorage(AccessSemantics semantics,
|
|
AccessKind accessKind, ModuleDecl *module,
|
|
ResilienceExpansion expansion) const;
|
|
|
|
/// Do we need to use resilient access patterns outside of this
|
|
/// property's resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// Do we need to use resilient access patterns when accessing this
|
|
/// property from the given module?
|
|
bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// True if the decl is resilient AND also its defining module does
|
|
/// _not_ allow non-resilient access; the module can allow such access
|
|
/// if package optimization is enabled so its client modules within the
|
|
/// same package can have a direct access to this decl even if it's
|
|
/// resilient.
|
|
bool isStrictlyResilient() const;
|
|
|
|
/// True if the storage can be referenced by a keypath directly.
|
|
/// Otherwise, its override must be referenced.
|
|
bool isValidKeyPathComponent() const;
|
|
|
|
/// If the storage exports a property descriptor for key paths in other
|
|
/// modules, this returns the generic signature in which its member methods
|
|
/// are emitted. If the storage does not export a property descriptor,
|
|
/// returns `std::nullopt`.
|
|
std::optional<GenericSignature>
|
|
getPropertyDescriptorGenericSignature() const;
|
|
|
|
/// True if any of the accessors to the storage is private or fileprivate.
|
|
bool hasPrivateAccessor() const;
|
|
|
|
bool hasDidSetOrWillSetDynamicReplacement() const;
|
|
|
|
bool hasAnyNativeDynamicAccessors() const;
|
|
|
|
/// Return a distributed thunk if this computed property is marked as
|
|
/// 'distributed' and and nullptr otherwise.
|
|
FuncDecl *getDistributedThunk() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_AbstractStorageDecl &&
|
|
D->getKind() <= DeclKind::Last_AbstractStorageDecl;
|
|
}
|
|
};
|
|
|
|
/// Describes which synthesized property for a property with an attached
|
|
/// wrapper is being referenced.
|
|
enum class PropertyWrapperSynthesizedPropertyKind {
|
|
/// The backing storage property, which is a stored property of the
|
|
/// wrapper type.
|
|
Backing,
|
|
/// A projection (e.g., `$foo`), which is a computed property to access the
|
|
/// wrapper instance's \c projectedValue property.
|
|
Projection,
|
|
};
|
|
|
|
/// VarDecl - 'var' and 'let' declarations.
|
|
class VarDecl : public AbstractStorageDecl {
|
|
friend class NamingPatternRequest;
|
|
friend class AttachedPropertyWrappersRequest;
|
|
friend class PropertyWrapperAuxiliaryVariablesRequest;
|
|
|
|
NamedPattern *NamingPattern = nullptr;
|
|
|
|
bool hasNoAttachedPropertyWrappers() const {
|
|
return Bits.VarDecl.NoAttachedPropertyWrappers;
|
|
}
|
|
|
|
void setHasNoAttachedPropertyWrappers() {
|
|
Bits.VarDecl.NoAttachedPropertyWrappers = true;
|
|
}
|
|
|
|
bool hasNoPropertyWrapperAuxiliaryVariables() const {
|
|
return Bits.VarDecl.NoPropertyWrapperAuxiliaryVariables;
|
|
}
|
|
|
|
void setHasNoPropertyWrapperAuxiliaryVariables() {
|
|
Bits.VarDecl.NoPropertyWrapperAuxiliaryVariables = true;
|
|
}
|
|
|
|
public:
|
|
enum class Introducer : uint8_t {
|
|
Let = 0,
|
|
Var = 1,
|
|
InOut = 2,
|
|
Borrowing = 3,
|
|
};
|
|
|
|
static StringRef getIntroducerStringRef(Introducer i) {
|
|
switch (i) {
|
|
case VarDecl::Introducer::Let:
|
|
return "let";
|
|
case VarDecl::Introducer::Var:
|
|
return "var";
|
|
case VarDecl::Introducer::InOut:
|
|
return "inout";
|
|
case VarDecl::Introducer::Borrowing:
|
|
return "_borrowing";
|
|
}
|
|
}
|
|
|
|
protected:
|
|
PointerUnion<PatternBindingDecl *,
|
|
Stmt *,
|
|
VarDecl *,
|
|
CaptureListExpr *> Parent;
|
|
|
|
VarDecl(DeclKind kind, bool isStatic, Introducer introducer,
|
|
SourceLoc nameLoc, Identifier name, DeclContext *dc,
|
|
StorageIsMutable_t supportsMutation);
|
|
|
|
public:
|
|
VarDecl(bool isStatic, Introducer introducer,
|
|
SourceLoc nameLoc, Identifier name, DeclContext *dc)
|
|
: VarDecl(DeclKind::Var, isStatic, introducer, nameLoc,
|
|
name, dc, StorageIsMutable_t(introducer == Introducer::Var)) {}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
Identifier getName() const { return getBaseIdentifier(); }
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
return hasName() ? getBaseIdentifier().str() : "_";
|
|
}
|
|
|
|
/// Maps the interface type of the variable declaration into the generic
|
|
/// environment of its parent DeclContext. Make sure this is what you want
|
|
/// and not just getInterfaceType().
|
|
Type getTypeInContext() const;
|
|
|
|
/// Determine the mutability of this variable declaration when
|
|
/// accessed from a given declaration context.
|
|
StorageMutability mutability(
|
|
const DeclContext *useDC,
|
|
std::optional<const DeclRefExpr *> base = std::nullopt) const;
|
|
|
|
/// Return the parent pattern binding that may provide an initializer for this
|
|
/// VarDecl. This returns null if there is none associated with the VarDecl.
|
|
PatternBindingDecl *getParentPatternBinding() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<PatternBindingDecl *>();
|
|
}
|
|
void setParentPatternBinding(PatternBindingDecl *PBD) {
|
|
assert(PBD);
|
|
Parent = PBD;
|
|
}
|
|
|
|
/// Return the Pattern involved in initializing this VarDecl. However, recall
|
|
/// that the Pattern may be involved in initializing more than just this one
|
|
/// vardecl. For example, if this is a VarDecl for "x", the pattern may be
|
|
/// "(x, y)" and the initializer on the PatternBindingDecl may be "(1,2)" or
|
|
/// "foo()".
|
|
///
|
|
/// If this has no parent pattern binding decl or statement associated, it
|
|
/// returns null.
|
|
///
|
|
Pattern *getParentPattern() const;
|
|
|
|
/// Returns the parsed type of this variable declaration. For parameters, this
|
|
/// is the parsed type the user explicitly wrote. For variables, this is the
|
|
/// type the user wrote in the typed pattern that binds this variable.
|
|
///
|
|
/// Note that there are many cases where the user may elide types. This will
|
|
/// return null in those cases.
|
|
TypeRepr *getTypeReprOrParentPatternTypeRepr() const;
|
|
|
|
/// Return the statement that owns the pattern associated with this VarDecl,
|
|
/// if one exists.
|
|
///
|
|
/// NOTE: After parsing and before type checking, all VarDecls from
|
|
/// CaseLabelItem's Patterns return their CaseStmt. After type checking, we
|
|
/// will have constructed the CaseLabelItem VarDecl linked list implying this
|
|
/// will return nullptr. After type checking, if one wishes to find a parent
|
|
/// pattern of a VarDecl of a CaseStmt, \see getRecursiveParentPatternStmt
|
|
/// instead.
|
|
Stmt *getParentPatternStmt() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<Stmt *>();
|
|
}
|
|
|
|
void setParentPatternStmt(Stmt *s) {
|
|
assert(s);
|
|
Parent = s;
|
|
}
|
|
|
|
/// Look for the parent pattern stmt of this var decl, recursively
|
|
/// looking through var decl pointers and then through any
|
|
/// fallthroughts.
|
|
Stmt *getRecursiveParentPatternStmt() const;
|
|
|
|
/// Returns the var decl that this var decl is an implicit reference to if
|
|
/// such a var decl exists.
|
|
VarDecl *getParentVarDecl() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<VarDecl *>();
|
|
}
|
|
|
|
/// Set \p v to be the pattern produced VarDecl that is the parent of this
|
|
/// var decl.
|
|
void setParentVarDecl(VarDecl *v) {
|
|
assert(v && v != this);
|
|
Parent = v;
|
|
}
|
|
|
|
NamedPattern *getNamingPattern() const;
|
|
void setNamingPattern(NamedPattern *Pat);
|
|
|
|
/// If this is a VarDecl that does not belong to a CaseLabelItem's pattern,
|
|
/// return this. Otherwise, this VarDecl must belong to a CaseStmt's
|
|
/// CaseLabelItem. In that case, return the first case label item of the first
|
|
/// case stmt in a sequence of case stmts that fallthrough into each other.
|
|
///
|
|
/// NOTE: During type checking, we emit an error if we have a single case
|
|
/// label item with a pattern that has multiple var decls of the same
|
|
/// name. This means that during type checking and before type checking, we
|
|
/// may have a _malformed_ switch stmt var decl linked list since var decls in
|
|
/// the same case label item that have the same name will point at the same
|
|
/// canonical var decl, namely the first var decl with the name in the
|
|
/// canonical case label item's var decl list. This is ok, since we are going
|
|
/// to emit the error, but it requires us to be more careful/cautious before
|
|
/// type checking has been complete when relying on canonical var decls
|
|
/// matching up.
|
|
VarDecl *getCanonicalVarDecl() const;
|
|
|
|
/// If this is a case stmt var decl, return the var decl that corresponds to
|
|
/// this var decl in the first case label item of the case stmt. Returns
|
|
/// nullptr if this isn't a VarDecl that is part of a case stmt.
|
|
NullablePtr<VarDecl> getCorrespondingFirstCaseLabelItemVarDecl() const;
|
|
|
|
/// If this is a case stmt var decl, return the case body var decl that this
|
|
/// var decl maps to.
|
|
NullablePtr<VarDecl> getCorrespondingCaseBodyVariable() const;
|
|
|
|
/// Return true if this var decl is an implicit var decl belonging to a case
|
|
/// stmt's body.
|
|
bool isCaseBodyVariable() const;
|
|
|
|
/// True if the global stored property requires lazy initialization.
|
|
bool isLazilyInitializedGlobal() const;
|
|
|
|
/// Return the initializer involved in this VarDecl. Recall that the
|
|
/// initializer may be involved in initializing more than just this one
|
|
/// vardecl though. For example, if this is a VarDecl for "x", the pattern
|
|
/// may be "(x, y)" and the initializer on the PatternBindingDecl may be
|
|
/// "(1,2)" or "foo()".
|
|
///
|
|
/// If this has no parent pattern binding decl associated, or if that pattern
|
|
/// binding has no initial value, this returns null.
|
|
///
|
|
Expr *getParentInitializer() const {
|
|
if (auto *PBD = getParentPatternBinding()) {
|
|
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
|
|
return PBD->getInit(i);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/// Whether there exists an initializer for this \c VarDecl.
|
|
bool isParentInitialized() const {
|
|
if (auto *PBD = getParentPatternBinding()) {
|
|
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
|
|
return PBD->isInitialized(i);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Return the initializer that will initializer this VarDecl at runtime.
|
|
/// This is equivalent to `getParentInitializer()`, but returns `null` if the
|
|
/// initializer itself was subsumed, e.g., by a macro or property wrapper.
|
|
Expr *getParentExecutableInitializer() const;
|
|
|
|
/// Whether this variable has an initializer that will be code-generated.
|
|
bool isParentExecutabledInitialized() const {
|
|
return getParentExecutableInitializer() != nullptr;
|
|
}
|
|
|
|
/// Get the required actor isolation for evaluating the initializer
|
|
/// expression synchronously (if there is one).
|
|
///
|
|
/// If this VarDecl is a stored instance property, the initializer
|
|
/// can only be used in an `init` that meets the required isolation.
|
|
/// Otherwise, the property must be explicitly initialized in the `init`.
|
|
///
|
|
/// If this is a ParamDecl, the initializer isolation is required at
|
|
/// the call-site in order to use the default argument for this parameter.
|
|
/// If the required isolation is not met, an argument must be written
|
|
/// explicitly at the call-site.
|
|
ActorIsolation getInitializerIsolation() const;
|
|
|
|
// Return whether this VarDecl has an initial value, either by checking
|
|
// if it has an initializer in its parent pattern binding or if it has
|
|
// the @_hasInitialValue attribute.
|
|
bool hasInitialValue() const {
|
|
return getAttrs().hasAttribute<HasInitialValueAttr>() ||
|
|
isParentInitialized();
|
|
}
|
|
|
|
VarDecl *getOverriddenDecl() const {
|
|
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Is this an immutable 'let' property?
|
|
///
|
|
/// For \c ParamDecl instances, using \c isImmutable is preferred.
|
|
bool isLet() const;
|
|
|
|
/// Is this an "async let" property?
|
|
bool isAsyncLet() const;
|
|
|
|
/// Is this var known to be a "local" distributed actor,
|
|
/// if so the implicit throwing and some isolation checks can be skipped.
|
|
bool isKnownToBeLocal() const;
|
|
|
|
/// Is this a stored property that will _not_ trigger any user-defined code
|
|
/// upon any kind of access?
|
|
bool isOrdinaryStoredProperty() const;
|
|
|
|
/// Set the introducer kind.
|
|
/// Note: do not call this after type checking begun.
|
|
void setIntroducer(Introducer value) {
|
|
Bits.VarDecl.Introducer = uint8_t(value);
|
|
}
|
|
|
|
Introducer getIntroducer() const {
|
|
return Introducer(Bits.VarDecl.Introducer);
|
|
}
|
|
|
|
StringRef getIntroducerStringRef() const {
|
|
return getIntroducerStringRef(getIntroducer());
|
|
}
|
|
|
|
CaptureListExpr *getParentCaptureList() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<CaptureListExpr *>();
|
|
}
|
|
|
|
/// Set \p v to be the pattern produced VarDecl that is the parent of this
|
|
/// var decl.
|
|
void setParentCaptureList(CaptureListExpr *expr) {
|
|
assert(expr != nullptr);
|
|
Parent = expr;
|
|
}
|
|
/// Is this an element in a capture list?
|
|
bool isCaptureList() const {
|
|
return getParentCaptureList() != nullptr;
|
|
}
|
|
|
|
/// Is this a capture of the self param?
|
|
bool isSelfParamCapture() const { return Bits.VarDecl.IsSelfParamCapture; }
|
|
void setIsSelfParamCapture(bool IsSelfParamCapture = true) {
|
|
Bits.VarDecl.IsSelfParamCapture = IsSelfParamCapture;
|
|
}
|
|
|
|
/// Check whether this capture of the self param is actor-isolated.
|
|
bool isSelfParamCaptureIsolated() const;
|
|
|
|
/// Determines if this var has an initializer expression that should be
|
|
/// exposed to clients.
|
|
///
|
|
/// There's a very narrow case when we would: if the decl is an instance
|
|
/// member with an initializer expression and the parent type is
|
|
/// @frozen and resides in a resilient module.
|
|
bool isInitExposedToClients() const;
|
|
|
|
/// Determines if this var is exposed as part of the layout of a
|
|
/// @frozen struct.
|
|
///
|
|
/// From the standpoint of access control and exportability checking, this
|
|
/// var will behave as if it was public, even if it is internal or private.
|
|
bool isLayoutExposedToClients() const;
|
|
|
|
/// Is this a special debugger variable?
|
|
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
|
void setDebuggerVar(bool IsDebuggerVar) {
|
|
Bits.VarDecl.IsDebuggerVar = IsDebuggerVar;
|
|
}
|
|
|
|
/// Visit all auxiliary declarations to this VarDecl.
|
|
///
|
|
/// An auxiliary declaration is a declaration synthesized by the compiler to support
|
|
/// this VarDecl, such as synthesized property wrapper variables.
|
|
///
|
|
/// \note this function only visits auxiliary decls that are not part of the AST.
|
|
void visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)>) const;
|
|
|
|
/// Is this the synthesized storage for a 'lazy' property?
|
|
bool isLazyStorageProperty() const {
|
|
return Bits.VarDecl.IsLazyStorageProperty;
|
|
}
|
|
void setLazyStorageProperty(bool IsLazyStorage) {
|
|
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
|
|
}
|
|
|
|
/// Retrieve the backing storage property for a lazy property.
|
|
VarDecl *getLazyStorageProperty() const;
|
|
|
|
/// True if this is a top-level global variable from the main source file.
|
|
bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; }
|
|
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
|
|
|
|
/// True if this is any storage of static duration (global scope or static).
|
|
bool isGlobalStorage() const;
|
|
|
|
/// Retrieve the custom attributes that attach property wrappers to this
|
|
/// property. The returned list contains all of the attached property wrapper
|
|
/// attributes in source order, which means the outermost wrapper attribute
|
|
/// is provided first.
|
|
llvm::TinyPtrVector<CustomAttr *> getAttachedPropertyWrappers() const;
|
|
|
|
/// Retrieve the outermost property wrapper attribute associated with
|
|
/// this declaration. For example:
|
|
///
|
|
/// \code
|
|
/// @A @B @C var <name>: Bool = ...
|
|
/// \endcode
|
|
///
|
|
/// The outermost attribute in this case is `@A` and it has
|
|
/// complete wrapper type `A<B<C<Bool>>>`.
|
|
CustomAttr *getOutermostAttachedPropertyWrapper() const {
|
|
auto wrappers = getAttachedPropertyWrappers();
|
|
return wrappers.empty() ? nullptr : wrappers.front();
|
|
}
|
|
|
|
/// Whether this property has any attached property wrappers.
|
|
bool hasAttachedPropertyWrapper() const;
|
|
|
|
/// Whether this var has an implicit property wrapper attribute.
|
|
bool hasImplicitPropertyWrapper() const;
|
|
|
|
/// Whether this var is a parameter with an attached property wrapper
|
|
/// that has an external effect on the function.
|
|
bool hasExternalPropertyWrapper() const;
|
|
|
|
/// Whether all of the attached property wrappers have an init(wrappedValue:)
|
|
/// initializer.
|
|
bool allAttachedPropertyWrappersHaveWrappedValueInit() const;
|
|
|
|
/// Retrieve the type of the attached property wrapper as a contextual
|
|
/// type.
|
|
///
|
|
/// \param index Which property wrapper type is being computed, where 0
|
|
/// indicates the first (outermost) attached property wrapper.
|
|
///
|
|
/// \returns a NULL type for properties without attached wrappers,
|
|
/// an error type when the property wrapper type itself is erroneous,
|
|
/// or the wrapper type itself, which may involve unbound generic
|
|
/// types.
|
|
Type getAttachedPropertyWrapperType(unsigned index) const;
|
|
|
|
/// Retrieve information about the attached property wrapper type.
|
|
///
|
|
/// \param i Which attached property wrapper type is being queried, where 0 is the outermost (first)
|
|
/// attached property wrapper type.
|
|
PropertyWrapperTypeInfo getAttachedPropertyWrapperTypeInfo(unsigned i) const;
|
|
|
|
/// Retrieve the fully resolved attached property wrapper type.
|
|
///
|
|
/// This type will be the fully-resolved form of
|
|
/// \c getAttachedPropertyWrapperType(0), which will not contain any
|
|
/// unbound generic types. It will be the type of the backing property.
|
|
Type getPropertyWrapperBackingPropertyType() const;
|
|
|
|
/// If there is an attached property wrapper, retrieve the synthesized
|
|
/// auxiliary variables.
|
|
PropertyWrapperAuxiliaryVariables
|
|
getPropertyWrapperAuxiliaryVariables() const;
|
|
|
|
/// If there is an attached property wrapper, retrieve information about
|
|
/// how to initialize the backing property.
|
|
PropertyWrapperInitializerInfo
|
|
getPropertyWrapperInitializerInfo() const;
|
|
|
|
/// Retrieve information about the mutability of the composed
|
|
/// property wrappers.
|
|
std::optional<PropertyWrapperMutability> getPropertyWrapperMutability() const;
|
|
|
|
/// Returns whether this property is the backing storage property or a storage
|
|
/// wrapper for wrapper instance's projectedValue. If this property is
|
|
/// neither, then it returns `None`.
|
|
std::optional<PropertyWrapperSynthesizedPropertyKind>
|
|
getPropertyWrapperSynthesizedPropertyKind() const;
|
|
|
|
/// Retrieve the backing storage property for a property that has an
|
|
/// attached property wrapper.
|
|
///
|
|
/// The backing storage property will be a stored property of the
|
|
/// wrapper's type. This will be equivalent to
|
|
/// \c getAttachedPropertyWrapperType(0) when it is fully-specified;
|
|
/// if \c getAttachedPropertyWrapperType(0) involves an unbound
|
|
/// generic type, the backing storage property will be the appropriate
|
|
/// bound generic version.
|
|
VarDecl *getPropertyWrapperBackingProperty() const;
|
|
|
|
/// Retrieve the projection var for a property that has an attached
|
|
/// property wrapper with a \c projectedValue .
|
|
VarDecl *getPropertyWrapperProjectionVar() const;
|
|
|
|
/// Retrieve the local wrapped value var for a parameter that has
|
|
/// an attached property wrapper.
|
|
VarDecl *getPropertyWrapperWrappedValueVar() const;
|
|
|
|
/// Return true if this property either has storage or has an attached property
|
|
/// wrapper that has storage.
|
|
bool hasStorageOrWrapsStorage() const;
|
|
|
|
/// Whether the memberwise initializer parameter for a property with a
|
|
/// property wrapper type uses the wrapped type. This will occur, for example,
|
|
/// when there is an explicitly-specified initializer like:
|
|
///
|
|
/// \code
|
|
/// @Lazy var i = 17
|
|
/// \endcode
|
|
///
|
|
/// Or when there is no initializer but each composed property wrapper has
|
|
/// a suitable `init(wrappedValue:)`.
|
|
bool isPropertyMemberwiseInitializedWithWrappedType() const;
|
|
|
|
/// Return the interface type of the value used for the 'wrappedValue:'
|
|
/// parameter when initializing a property wrapper.
|
|
///
|
|
/// If the property has an attached property wrapper and the 'wrappedValue:'
|
|
/// parameter is an autoclosure, return a function type returning the stored
|
|
/// value. Otherwise, return the interface type of the stored value.
|
|
Type getPropertyWrapperInitValueInterfaceType() const;
|
|
|
|
/// If this property is the backing storage for a property with an attached
|
|
/// property wrapper, return the original property.
|
|
///
|
|
/// \param kind If not \c None, only returns the original property when
|
|
/// \c this property is the specified synthesized property.
|
|
VarDecl *getOriginalWrappedProperty(
|
|
std::optional<PropertyWrapperSynthesizedPropertyKind> kind =
|
|
std::nullopt) const;
|
|
|
|
/// Set the property that wraps to this property as it's backing
|
|
/// property.
|
|
void setOriginalWrappedProperty(VarDecl *originalProperty);
|
|
|
|
/// Return the Objective-C runtime name for this property.
|
|
Identifier getObjCPropertyName() const;
|
|
|
|
/// Retrieve the default Objective-C selector for the getter of a
|
|
/// property of the given name.
|
|
static ObjCSelector getDefaultObjCGetterSelector(ASTContext &ctx,
|
|
Identifier propertyName);
|
|
|
|
/// Retrieve the default Objective-C selector for the setter of a
|
|
/// property of the given name.
|
|
static ObjCSelector getDefaultObjCSetterSelector(ASTContext &ctx,
|
|
Identifier propertyName);
|
|
|
|
/// If this is a simple 'let' constant, emit a note with a fixit indicating
|
|
/// that it can be rewritten to a 'var'. This is used in situations where the
|
|
/// compiler detects obvious attempts to mutate a constant.
|
|
void emitLetToVarNoteIfSimple(DeclContext *UseDC) const;
|
|
|
|
/// Returns true if the name is the self identifier and is implicit.
|
|
bool isSelfParameter() const;
|
|
|
|
/// Check whether the variable is the "self" of an actor method.
|
|
bool isActorSelf() const;
|
|
|
|
/// Determine whether this property will be part of the implicit memberwise
|
|
/// initializer.
|
|
///
|
|
/// \param preferDeclaredProperties When encountering a `lazy` property
|
|
/// or a property that has an attached property wrapper, prefer the
|
|
/// actual declared property (which may or may not be considered "stored"
|
|
/// as the moment) to the backing storage property. Otherwise, the stored
|
|
/// backing property will be treated as the member-initialized property.
|
|
bool isMemberwiseInitialized(bool preferDeclaredProperties) const;
|
|
|
|
/// Return the range of semantics attributes attached to this VarDecl.
|
|
auto getSemanticsAttrs() const
|
|
-> decltype(getAttrs().getAttributes<SemanticsAttr>()) {
|
|
return getAttrs().getAttributes<SemanticsAttr>();
|
|
}
|
|
|
|
/// Returns true if this VarDecl has the string \p attrValue as a semantics
|
|
/// attribute.
|
|
bool hasSemanticsAttr(StringRef attrValue) const {
|
|
return llvm::any_of(getSemanticsAttrs(), [&](const SemanticsAttr *attr) {
|
|
return attrValue == attr->Value;
|
|
});
|
|
}
|
|
|
|
clang::PointerAuthQualifier getPointerAuthQualifier() const;
|
|
|
|
static VarDecl *createImplicitStringInterpolationVar(DeclContext *DC);
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param;
|
|
}
|
|
};
|
|
|
|
/// A function parameter declaration.
|
|
class ParamDecl : public VarDecl {
|
|
friend class ParameterList;
|
|
friend class DefaultArgumentInitContextRequest;
|
|
friend class DefaultArgumentExprRequest;
|
|
friend class DefaultArgumentTypeRequest;
|
|
|
|
enum class ArgumentNameFlags : uint8_t {
|
|
/// Whether or not this parameter is destructed.
|
|
Destructured = 1 << 0,
|
|
|
|
/// Whether or not this parameter is '_const'.
|
|
IsCompileTimeLiteral = 1 << 1,
|
|
|
|
/// Whether or not this parameter is '@const'.
|
|
IsConstValue = 1 << 2,
|
|
};
|
|
|
|
llvm::PointerIntPair<Identifier, 3, OptionSet<ArgumentNameFlags>>
|
|
ArgumentNameAndFlags;
|
|
SourceLoc ParameterNameLoc;
|
|
SourceLoc ArgumentNameLoc;
|
|
SourceLoc SpecifierLoc;
|
|
|
|
struct alignas(1 << StoredDefaultArgumentAlignInBits) StoredDefaultArgument {
|
|
PointerUnion<Expr *, VarDecl *> DefaultArg;
|
|
|
|
/// The type of the default argument expression.
|
|
Type ExprType;
|
|
|
|
/// Stores the context for the default argument as well as a bit to
|
|
/// indicate whether the default expression has been type-checked.
|
|
llvm::PointerIntPair<DefaultArgumentInitializer *, 1, bool>
|
|
InitContextAndIsTypeChecked;
|
|
|
|
StringRef StringRepresentation;
|
|
CaptureInfo Captures;
|
|
};
|
|
|
|
/// Retrieve the cached initializer context for the parameter's default
|
|
/// argument without triggering a request.
|
|
std::optional<DefaultArgumentInitializer *>
|
|
getCachedDefaultArgumentInitContext() const;
|
|
|
|
/// NOTE: This is stored using bits from TyReprAndFlags and
|
|
/// DefaultValueAndFlags.
|
|
enum class Flag : uint8_t {
|
|
/// Whether or not this parameter is vargs.
|
|
IsVariadic = 1 << 0,
|
|
|
|
/// Whether or not this parameter is `@autoclosure`.
|
|
IsAutoClosure = 1 << 1,
|
|
|
|
/// Whether or not this parameter is 'isolated'.
|
|
IsIsolated = 1 << 2,
|
|
|
|
/// Whether this parameter is `@_addressable`.
|
|
IsAddressable = 1 << 3,
|
|
|
|
/// Whether or not this parameter is 'sending'.
|
|
IsSending = 1 << 4,
|
|
|
|
/// Whether or not this parameter is isolated to a caller.
|
|
IsCallerIsolated = 1 << 5,
|
|
};
|
|
|
|
/// The type repr and 3 bits used for flags.
|
|
llvm::PointerIntPair<TypeRepr *, 3, std::underlying_type<Flag>::type>
|
|
TyReprAndFlags;
|
|
|
|
/// The default value, if any, along with 3 bits for flags.
|
|
llvm::PointerIntPair<StoredDefaultArgument *, 3,
|
|
std::underlying_type<Flag>::type>
|
|
DefaultValueAndFlags;
|
|
|
|
OptionSet<Flag> getOptions() const {
|
|
uint8_t result = 0;
|
|
result |= TyReprAndFlags.getInt();
|
|
result |= DefaultValueAndFlags.getInt() << 3;
|
|
return OptionSet<Flag>(result);
|
|
}
|
|
|
|
/// Set the current set of options to \p newFlags.
|
|
void setOptions(OptionSet<Flag> newFlags) {
|
|
uint8_t bits = newFlags.toRaw();
|
|
TyReprAndFlags.setInt(bits & 0x7);
|
|
DefaultValueAndFlags.setInt(bits >> 3);
|
|
}
|
|
|
|
void setOptionsAndPointers(TypeRepr *tyRepr,
|
|
StoredDefaultArgument *storedArgs,
|
|
OptionSet<Flag> newFlags) {
|
|
uint8_t bits = newFlags.toRaw();
|
|
TyReprAndFlags.setPointerAndInt(tyRepr, bits & 0x7);
|
|
DefaultValueAndFlags.setPointerAndInt(storedArgs, bits >> 3);
|
|
}
|
|
|
|
void addFlag(Flag newFlag) {
|
|
auto flagBits = uint8_t(newFlag);
|
|
if (uint8_t(newFlag) < (1 << 3)) {
|
|
flagBits &= 0x7;
|
|
TyReprAndFlags.setInt(TyReprAndFlags.getInt() | flagBits);
|
|
return;
|
|
}
|
|
|
|
flagBits >>= 3;
|
|
DefaultValueAndFlags.setInt(DefaultValueAndFlags.getInt() | flagBits);
|
|
}
|
|
|
|
void removeFlag(Flag newFlag) {
|
|
auto flagBits = uint8_t(newFlag);
|
|
if (uint8_t(newFlag) < (1 << 3)) {
|
|
flagBits &= 0x7;
|
|
TyReprAndFlags.setInt(TyReprAndFlags.getInt() & ~flagBits);
|
|
return;
|
|
}
|
|
|
|
flagBits >>= 3;
|
|
DefaultValueAndFlags.setInt(DefaultValueAndFlags.getInt() & ~flagBits);
|
|
}
|
|
|
|
friend class ParamSpecifierRequest;
|
|
|
|
public:
|
|
ParamDecl(SourceLoc specifierLoc, SourceLoc argumentNameLoc,
|
|
Identifier argumentName, SourceLoc parameterNameLoc,
|
|
Identifier parameterName, DeclContext *dc);
|
|
|
|
/// Create a new `ParamDecl` identical to the given one except without the
|
|
/// interface type.
|
|
///
|
|
/// \param PD The parameter to clone.
|
|
/// \param defaultArgKind The default argument kind for the cloned parameter.
|
|
/// If \c std::nullopt, use the default argument kind of \p PD.
|
|
static ParamDecl *cloneWithoutType(
|
|
const ASTContext &Ctx, ParamDecl *PD,
|
|
std::optional<DefaultArgumentKind> defaultArgKind = std::nullopt);
|
|
|
|
/// Create a an identical copy of this ParamDecl.
|
|
static ParamDecl *clone(const ASTContext &Ctx, ParamDecl *PD);
|
|
|
|
static ParamDecl *cloneAccessor(const ASTContext &Ctx,
|
|
ParamDecl const *subscriptParam,
|
|
DeclContext *Parent);
|
|
|
|
static ParamDecl *
|
|
createImplicit(ASTContext &Context, SourceLoc specifierLoc,
|
|
SourceLoc argumentNameLoc, Identifier argumentName,
|
|
SourceLoc parameterNameLoc, Identifier parameterName,
|
|
Type interfaceType, DeclContext *Parent,
|
|
ParamSpecifier specifier = ParamSpecifier::Default);
|
|
|
|
static ParamDecl *
|
|
createImplicit(ASTContext &Context, Identifier argumentName,
|
|
Identifier parameterName, Type interfaceType,
|
|
DeclContext *Parent,
|
|
ParamSpecifier specifier = ParamSpecifier::Default);
|
|
|
|
static ParamDecl *createParsed(
|
|
ASTContext &Context, SourceLoc specifierLoc, SourceLoc argumentNameLoc,
|
|
Identifier argumentName, SourceLoc parameterNameLoc,
|
|
Identifier parameterName, Expr *defaultValue,
|
|
DefaultArgumentInitializer *defaultValueInitContext, DeclContext *dc);
|
|
|
|
/// Retrieve the argument (API) name for this function parameter.
|
|
Identifier getArgumentName() const {
|
|
return ArgumentNameAndFlags.getPointer();
|
|
}
|
|
|
|
/// Retrieve the parameter (local) name for this function parameter.
|
|
Identifier getParameterName() const { return getName(); }
|
|
|
|
/// Retrieve the source location of the argument (API) name.
|
|
///
|
|
/// The resulting source location will be valid if the argument name
|
|
/// was specified separately from the parameter name.
|
|
SourceLoc getArgumentNameLoc() const { return ArgumentNameLoc; }
|
|
|
|
SourceLoc getParameterNameLoc() const { return ParameterNameLoc; }
|
|
|
|
SourceLoc getSpecifierLoc() const { return SpecifierLoc; }
|
|
|
|
/// Retrieve the TypeRepr corresponding to the parsed type of the parameter, if it exists.
|
|
TypeRepr *getTypeRepr() const { return TyReprAndFlags.getPointer(); }
|
|
|
|
/// Set the parsed TypeRepr on the parameter.
|
|
void setTypeRepr(TypeRepr *repr);
|
|
|
|
bool isDestructured() const {
|
|
auto flags = ArgumentNameAndFlags.getInt();
|
|
return flags.contains(ArgumentNameFlags::Destructured);
|
|
}
|
|
|
|
void setDestructured(bool repr) {
|
|
auto flags = ArgumentNameAndFlags.getInt();
|
|
flags = repr ? flags | ArgumentNameFlags::Destructured
|
|
: flags - ArgumentNameFlags::Destructured;
|
|
ArgumentNameAndFlags.setInt(flags);
|
|
}
|
|
|
|
DefaultArgumentKind getDefaultArgumentKind() const {
|
|
return static_cast<DefaultArgumentKind>(Bits.ParamDecl.defaultArgumentKind);
|
|
}
|
|
bool isDefaultArgument() const {
|
|
return getDefaultArgumentKind() != DefaultArgumentKind::None;
|
|
}
|
|
|
|
void setDefaultArgumentKind(DefaultArgumentKind K);
|
|
|
|
void setDefaultArgumentKind(ArgumentAttrs K) {
|
|
setDefaultArgumentKind(K.argumentKind);
|
|
}
|
|
|
|
/// Whether this parameter has a default argument expression available.
|
|
///
|
|
/// Note that this will return false for deserialized declarations, which only
|
|
/// have a textual representation of their default expression.
|
|
bool hasDefaultExpr() const;
|
|
|
|
/// Whether this parameter has a caller-side default argument expression
|
|
/// such as the magic literal \c #function.
|
|
bool hasCallerSideDefaultExpr() const;
|
|
|
|
/// Retrieve the fully type-checked default argument expression for this
|
|
/// parameter, or \c nullptr if there is no default expression.
|
|
///
|
|
/// Note that while this will produce a type-checked expression for
|
|
/// caller-side default arguments such as \c #function, this is done purely to
|
|
/// check whether the code is valid. Such default arguments get re-created
|
|
/// at the call site in order to have the correct context information.
|
|
Expr *getTypeCheckedDefaultExpr() const;
|
|
|
|
/// Retrieve the potentially un-type-checked default argument expression for
|
|
/// this parameter, which can be queried for information such as its source
|
|
/// range and textual representation. Returns \c nullptr if there is no
|
|
/// default expression.
|
|
Expr *getStructuralDefaultExpr() const {
|
|
if (auto stored = DefaultValueAndFlags.getPointer())
|
|
return stored->DefaultArg.dyn_cast<Expr *>();
|
|
return nullptr;
|
|
}
|
|
|
|
/// Retrieve the type of the default expression (if any) associated with
|
|
/// this parameter declaration.
|
|
Type getTypeOfDefaultExpr() const;
|
|
|
|
VarDecl *getStoredProperty() const {
|
|
if (auto stored = DefaultValueAndFlags.getPointer())
|
|
return stored->DefaultArg.dyn_cast<VarDecl *>();
|
|
return nullptr;
|
|
}
|
|
|
|
/// Sets a new default argument expression for this parameter. This should
|
|
/// only be called internally by `ParamDecl` and `ASTWalker`.
|
|
///
|
|
/// \param E The new default argument.
|
|
void setDefaultExpr(Expr *E);
|
|
|
|
// FIXME: private:
|
|
/// Sets a type-checked default argument expression for this parameter. This
|
|
/// should only be called by the `DefaultArgumentExprRequest` request.
|
|
///
|
|
/// \param E The type-checked default argument.
|
|
void setTypeCheckedDefaultExpr(Expr *E);
|
|
|
|
public:
|
|
/// Sets a type of default expression associated with this parameter.
|
|
/// This should only be called by deserialization.
|
|
void setDefaultExprType(Type type);
|
|
|
|
void setStoredProperty(VarDecl *var);
|
|
|
|
/// Retrieve the initializer context for the parameter's default argument.
|
|
Initializer *getDefaultArgumentInitContext() const;
|
|
|
|
void setDefaultArgumentInitContext(DefaultArgumentInitializer *initContext);
|
|
|
|
CaptureInfo getDefaultArgumentCaptureInfo() const;
|
|
|
|
std::optional<CaptureInfo> getCachedDefaultArgumentCaptureInfo() const {
|
|
assert(DefaultValueAndFlags.getPointer());
|
|
const auto &captures = DefaultValueAndFlags.getPointer()->Captures;
|
|
if (!captures.hasBeenComputed())
|
|
return std::nullopt;
|
|
return captures;
|
|
}
|
|
|
|
void setDefaultArgumentCaptureInfo(CaptureInfo captures);
|
|
|
|
/// Extracts the text of the default argument attached to the provided
|
|
/// ParamDecl, removing all inactive #if clauses and providing only the
|
|
/// text of active #if clauses.
|
|
///
|
|
/// For example, the default argument:
|
|
/// ```
|
|
/// {
|
|
/// #if false
|
|
/// print("false")
|
|
/// #else
|
|
/// print("true")
|
|
/// #endif
|
|
/// }
|
|
/// ```
|
|
/// will return
|
|
/// ```
|
|
/// {
|
|
/// print("true")
|
|
/// }
|
|
/// ```
|
|
/// \sa getDefaultValue
|
|
StringRef getDefaultValueStringRepresentation(
|
|
SmallVectorImpl<char> &scratch) const;
|
|
|
|
void setDefaultValueStringRepresentation(StringRef stringRepresentation);
|
|
|
|
/// Whether or not this parameter is old-style variadic.
|
|
bool isVariadic() const;
|
|
void setVariadic(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsVariadic);
|
|
else
|
|
removeFlag(Flag::IsVariadic);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with `@autoclosure`.
|
|
bool isAutoClosure() const {
|
|
return getOptions().contains(Flag::IsAutoClosure);
|
|
}
|
|
|
|
void setAutoClosure(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsAutoClosure);
|
|
else
|
|
removeFlag(Flag::IsAutoClosure);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with 'isolated'.
|
|
bool isIsolated() const { return getOptions().contains(Flag::IsIsolated); }
|
|
|
|
void setIsolated(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsIsolated);
|
|
else
|
|
removeFlag(Flag::IsIsolated);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with 'sending'.
|
|
bool isSending() const { return getOptions().contains(Flag::IsSending); }
|
|
|
|
void setSending(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsSending);
|
|
else
|
|
removeFlag(Flag::IsSending);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with 'nonisolated(nonsending)'.
|
|
bool isCallerIsolated() const {
|
|
return getOptions().contains(Flag::IsCallerIsolated);
|
|
}
|
|
|
|
void setCallerIsolated(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsCallerIsolated);
|
|
else
|
|
removeFlag(Flag::IsCallerIsolated);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with '@_addressable'.
|
|
bool isAddressable() const {
|
|
return getOptions().contains(Flag::IsAddressable);
|
|
}
|
|
|
|
void setAddressable(bool value = true) {
|
|
if (value)
|
|
addFlag(Flag::IsAddressable);
|
|
else
|
|
removeFlag(Flag::IsAddressable);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with '_const'.
|
|
bool isCompileTimeLiteral() const {
|
|
return ArgumentNameAndFlags.getInt().contains(
|
|
ArgumentNameFlags::IsCompileTimeLiteral);
|
|
}
|
|
|
|
void setCompileTimeLiteral(bool value = true) {
|
|
auto flags = ArgumentNameAndFlags.getInt();
|
|
flags = value ? flags | ArgumentNameFlags::IsCompileTimeLiteral
|
|
: flags - ArgumentNameFlags::IsCompileTimeLiteral;
|
|
ArgumentNameAndFlags.setInt(flags);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with '@const'.
|
|
bool isConstVal() const {
|
|
return ArgumentNameAndFlags.getInt().contains(
|
|
ArgumentNameFlags::IsConstValue);
|
|
}
|
|
|
|
void setConstValue(bool value = true) {
|
|
auto flags = ArgumentNameAndFlags.getInt();
|
|
flags = value ? flags | ArgumentNameFlags::IsConstValue
|
|
: flags - ArgumentNameFlags::IsConstValue;
|
|
ArgumentNameAndFlags.setInt(flags);
|
|
}
|
|
|
|
/// Does this parameter reject temporary pointer conversions?
|
|
bool isNonEphemeral() const;
|
|
|
|
/// Attempt to apply an implicit `@_nonEphemeral` attribute to this parameter.
|
|
void setNonEphemeralIfPossible();
|
|
|
|
/// Remove the type of this varargs element designator, without the array
|
|
/// type wrapping it. A parameter like "Int..." will have formal parameter
|
|
/// type of "[Int]" and this returns "Int".
|
|
static Type getVarargBaseTy(Type VarArgT);
|
|
|
|
/// Remove the type of this varargs element designator, without the array
|
|
/// type wrapping it.
|
|
Type getVarargBaseTy() const {
|
|
assert(isVariadic());
|
|
return getVarargBaseTy(getInterfaceType());
|
|
}
|
|
|
|
/// Determine whether this declaration is an anonymous closure parameter.
|
|
bool isAnonClosureParam() const;
|
|
|
|
using Specifier = ParamSpecifier;
|
|
|
|
std::optional<Specifier> getCachedSpecifier() const {
|
|
if (Bits.ParamDecl.OwnershipSpecifier != 0)
|
|
return Specifier(Bits.ParamDecl.OwnershipSpecifier - 1);
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
/// Return the raw specifier value for this parameter.
|
|
Specifier getSpecifier() const;
|
|
void setSpecifier(Specifier Spec);
|
|
|
|
LifetimeAnnotation getLifetimeAnnotation() const;
|
|
|
|
/// Is the type of this parameter 'inout'?
|
|
bool isInOut() const { return getSpecifier() == Specifier::InOut; }
|
|
|
|
bool isImmutableInFunctionBody() const {
|
|
return isSpecifierImmutableInFunctionBody(getSpecifier());
|
|
}
|
|
static bool isSpecifierImmutableInFunctionBody(Specifier sp) {
|
|
switch (sp) {
|
|
case Specifier::Default:
|
|
case Specifier::Borrowing:
|
|
case Specifier::LegacyShared:
|
|
case Specifier::LegacyOwned:
|
|
return true;
|
|
case Specifier::Consuming:
|
|
case Specifier::InOut:
|
|
case Specifier::ImplicitlyCopyableConsuming:
|
|
return false;
|
|
}
|
|
llvm_unreachable("unhandled specifier");
|
|
}
|
|
|
|
ValueOwnership getValueOwnership() const {
|
|
return getValueOwnershipForSpecifier(getSpecifier());
|
|
}
|
|
|
|
static ValueOwnership getValueOwnershipForSpecifier(Specifier specifier) {
|
|
switch (specifier) {
|
|
case ParamSpecifier::InOut:
|
|
return ValueOwnership::InOut;
|
|
case ParamSpecifier::Borrowing:
|
|
case ParamSpecifier::LegacyShared:
|
|
return ValueOwnership::Shared;
|
|
case ParamSpecifier::Consuming:
|
|
case ParamSpecifier::ImplicitlyCopyableConsuming:
|
|
case ParamSpecifier::LegacyOwned:
|
|
return ValueOwnership::Owned;
|
|
case ParamSpecifier::Default:
|
|
return ValueOwnership::Default;
|
|
}
|
|
llvm_unreachable("invalid ParamSpecifier");
|
|
}
|
|
|
|
static Specifier
|
|
getParameterSpecifierForValueOwnership(ValueOwnership ownership) {
|
|
// TODO: switch over to consuming/borrowing once they're fully supported
|
|
switch (ownership) {
|
|
case ValueOwnership::Default:
|
|
return Specifier::Default;
|
|
case ValueOwnership::Shared:
|
|
return Specifier::LegacyShared; // should become Borrowing
|
|
case ValueOwnership::InOut:
|
|
return Specifier::InOut;
|
|
case ValueOwnership::Owned:
|
|
return Specifier::LegacyOwned; // should become Consuming
|
|
}
|
|
llvm_unreachable("unhandled ownership");
|
|
}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
AnyFunctionType::Param toFunctionParam(Type type = Type()) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Param;
|
|
}
|
|
|
|
/// Get the source code spelling of a parameter specifier value as a string.
|
|
static StringRef getSpecifierSpelling(Specifier spec);
|
|
};
|
|
|
|
inline ValueOwnership
|
|
ParameterTypeFlags::getValueOwnership() const {
|
|
return ParamDecl::getValueOwnershipForSpecifier(getOwnershipSpecifier());
|
|
}
|
|
|
|
inline ValueOwnership
|
|
YieldTypeFlags::getValueOwnership() const {
|
|
return ParamDecl::getValueOwnershipForSpecifier(getOwnershipSpecifier());
|
|
}
|
|
|
|
/// Describes the kind of subscripting used in Objective-C.
|
|
enum class ObjCSubscriptKind {
|
|
/// Objective-C indexed subscripting, which is based on an integral
|
|
/// index.
|
|
Indexed,
|
|
/// Objective-C keyed subscripting, which is based on an object
|
|
/// argument or metatype thereof.
|
|
Keyed
|
|
};
|
|
|
|
/// Declares a subscripting operator for a type.
|
|
///
|
|
/// A subscript declaration is defined as a get/set pair that produces a
|
|
/// specific type. For example:
|
|
///
|
|
/// \code
|
|
/// subscript (i : Int) -> String {
|
|
/// get { /* return ith String */ }
|
|
/// set { /* set ith string to value */ }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// A type with a subscript declaration can be used as the base of a subscript
|
|
/// expression a[i], where a is of the subscriptable type and i is the type
|
|
/// of the index. A subscript can have multiple indices:
|
|
///
|
|
/// \code
|
|
/// struct Matrix {
|
|
/// subscript (i : Int, j : Int) -> Double {
|
|
/// get { /* return element at position (i, j) */ }
|
|
/// set { /* set element at position (i, j) */ }
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// A given type can have multiple subscript declarations, so long as the
|
|
/// signatures (indices and element type) are distinct.
|
|
///
|
|
class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
|
|
friend class ResultTypeRequest;
|
|
|
|
SourceLoc StaticLoc;
|
|
SourceLoc ArrowLoc;
|
|
ParameterList *Indices;
|
|
TypeLoc ElementTy;
|
|
|
|
void setElementInterfaceType(Type type);
|
|
|
|
SubscriptDecl(DeclName Name,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc SubscriptLoc, ParameterList *Indices,
|
|
SourceLoc ArrowLoc, TypeRepr *ElementTyR, DeclContext *Parent,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::SubscriptDecl, Parent, GenericParams),
|
|
AbstractStorageDecl(DeclKind::Subscript,
|
|
StaticSpelling != StaticSpellingKind::None,
|
|
Parent, Name, SubscriptLoc,
|
|
/*will be overwritten*/ StorageIsNotMutable),
|
|
StaticLoc(StaticLoc), ArrowLoc(ArrowLoc),
|
|
Indices(nullptr), ElementTy(ElementTyR) {
|
|
Bits.SubscriptDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
setIndices(Indices);
|
|
}
|
|
|
|
public:
|
|
/// Factory function only for use by deserialization.
|
|
static SubscriptDecl *createDeserialized(ASTContext &Context, DeclName Name,
|
|
StaticSpellingKind StaticSpelling,
|
|
Type ElementTy, DeclContext *Parent,
|
|
GenericParamList *GenericParams);
|
|
|
|
static SubscriptDecl *createParsed(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc SubscriptLoc,
|
|
ParameterList *Indices, SourceLoc ArrowLoc,
|
|
TypeRepr *ElementTyR, DeclContext *Parent,
|
|
GenericParamList *GenericParams);
|
|
|
|
static SubscriptDecl *create(ASTContext &Context, DeclName Name,
|
|
SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc SubscriptLoc, ParameterList *Indices,
|
|
SourceLoc ArrowLoc, Type ElementTy,
|
|
DeclContext *Parent,
|
|
GenericParamList *GenericParams);
|
|
|
|
static SubscriptDecl *createImported(ASTContext &Context, DeclName Name,
|
|
SourceLoc SubscriptLoc,
|
|
ParameterList *Indices,
|
|
SourceLoc ArrowLoc, Type ElementTy,
|
|
DeclContext *Parent,
|
|
GenericParamList *GenericParams,
|
|
ClangNode ClangN);
|
|
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(Bits.SubscriptDecl.StaticSpelling);
|
|
}
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getSubscriptLoc() const { return getNameLoc(); }
|
|
|
|
SourceRange getSourceRange() const;
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
/// Retrieve the indices for this subscript operation.
|
|
ParameterList *getIndices() { return Indices; }
|
|
const ParameterList *getIndices() const { return Indices; }
|
|
void setIndices(ParameterList *p);
|
|
|
|
/// Retrieve the type of the element referenced by a subscript
|
|
/// operation.
|
|
Type getElementInterfaceType() const;
|
|
|
|
std::optional<Type> getCachedElementInterfaceType() const;
|
|
|
|
TypeRepr *getElementTypeRepr() const { return ElementTy.getTypeRepr(); }
|
|
SourceRange getElementTypeSourceRange() const {
|
|
return ElementTy.getSourceRange();
|
|
}
|
|
|
|
/// Determine the kind of Objective-C subscripting this declaration
|
|
/// implies.
|
|
ObjCSubscriptKind getObjCSubscriptKind() const;
|
|
|
|
SubscriptDecl *getOverriddenDecl() const {
|
|
return cast_or_null<SubscriptDecl>(
|
|
AbstractStorageDecl::getOverriddenDecl());
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Subscript;
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
/// Encodes imported-as-member status for C functions that get imported
|
|
/// as methods.
|
|
class ImportAsMemberStatus {
|
|
friend class AbstractFunctionDecl;
|
|
|
|
// non-0 denotes import-as-member. 1 denotes no self index. n+2 denotes self
|
|
// index of n
|
|
uint8_t rawValue;
|
|
|
|
public:
|
|
ImportAsMemberStatus(uint8_t rawValue = 0) : rawValue(rawValue) {}
|
|
|
|
uint8_t getRawValue() const { return rawValue; }
|
|
|
|
bool isImportAsMember() const { return rawValue != 0; }
|
|
bool isInstance() const { return rawValue >= 2; }
|
|
bool isStatic() const { return rawValue == 1; }
|
|
uint8_t getSelfIndex() const {
|
|
assert(isInstance() && "not set");
|
|
return rawValue - 2;
|
|
}
|
|
void setStatic() {
|
|
assert(!isStatic() && "already set");
|
|
rawValue = 1;
|
|
}
|
|
void setSelfIndex(uint8_t idx) {
|
|
assert(!isImportAsMember() && "already set");
|
|
assert(idx <= UINT8_MAX-2 && "out of bounds");
|
|
rawValue = idx + 2;
|
|
}
|
|
};
|
|
|
|
class BodyAndFingerprint {
|
|
llvm::PointerIntPair<BraceStmt *, 1, bool> BodyAndHasFp;
|
|
Fingerprint Fp;
|
|
|
|
public:
|
|
BodyAndFingerprint(BraceStmt *body, std::optional<Fingerprint> fp)
|
|
: BodyAndHasFp(body, fp.has_value()),
|
|
Fp(fp.has_value() ? *fp : Fingerprint::ZERO()) {}
|
|
BodyAndFingerprint() : BodyAndFingerprint(nullptr, std::nullopt) {}
|
|
|
|
BraceStmt *getBody() const { return BodyAndHasFp.getPointer(); }
|
|
|
|
std::optional<Fingerprint> getFingerprint() const {
|
|
if (BodyAndHasFp.getInt())
|
|
return Fp;
|
|
else
|
|
return std::nullopt;
|
|
}
|
|
|
|
void setFingerprint(std::optional<Fingerprint> fp) {
|
|
if (fp.has_value()) {
|
|
Fp = *fp;
|
|
BodyAndHasFp.setInt(true);
|
|
} else {
|
|
Fp = Fingerprint::ZERO();
|
|
BodyAndHasFp.setInt(false);
|
|
}
|
|
}
|
|
};
|
|
|
|
void simple_display(llvm::raw_ostream &out, BodyAndFingerprint value);
|
|
|
|
/// Base class for function-like declarations.
|
|
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
|
|
friend class NeedsNewVTableEntryRequest;
|
|
friend class ExplicitCaughtTypeRequest;
|
|
|
|
public:
|
|
/// records the kind of SILGen-synthesized body this decl represents
|
|
enum class SILSynthesizeKind {
|
|
None,
|
|
MemberwiseInitializer,
|
|
DistributedActorFactory
|
|
|
|
// This enum currently needs to fit in a 2-bit bitfield.
|
|
};
|
|
|
|
enum class BodyKind {
|
|
/// The function did not have a body in the source code file.
|
|
None,
|
|
|
|
/// Function body is delayed, to be parsed later.
|
|
Unparsed,
|
|
|
|
/// Function body is parsed and available as an AST subtree.
|
|
Parsed,
|
|
|
|
/// Function body will be synthesized on demand.
|
|
Synthesize,
|
|
|
|
/// Function body is present and type-checked.
|
|
TypeChecked,
|
|
|
|
// Function body will be synthesized by SILGen.
|
|
SILSynthesize,
|
|
|
|
/// Function body text was deserialized from a .swiftmodule.
|
|
Deserialized
|
|
|
|
// This enum currently needs to fit in a 3-bit bitfield.
|
|
};
|
|
|
|
enum class BodySkippedStatus {
|
|
Unknown,
|
|
Skipped,
|
|
NotSkipped,
|
|
|
|
// This enum needs to fit in a 2-bit bitfield.
|
|
};
|
|
|
|
enum class BodyExpandedStatus {
|
|
/// We haven't tried to expand any body macros.
|
|
NotExpanded,
|
|
|
|
/// We tried to expand body macros, and there weren't any.
|
|
NoMacros,
|
|
|
|
/// The body was expanded from a body macro.
|
|
Expanded,
|
|
|
|
// This enum needs to fit in a 2-bit bitfield.
|
|
};
|
|
|
|
BodyKind getBodyKind() const {
|
|
return BodyKind(Bits.AbstractFunctionDecl.BodyKind);
|
|
}
|
|
|
|
struct BodySynthesizer {
|
|
std::pair<BraceStmt *, bool> (* Fn)(AbstractFunctionDecl *, void *);
|
|
void *Context;
|
|
};
|
|
|
|
private:
|
|
ParameterList *Params;
|
|
|
|
private:
|
|
/// The generation at which we last loaded derivative function configurations.
|
|
unsigned DerivativeFunctionConfigGeneration = 0;
|
|
/// Prepare to traverse the list of derivative function configurations.
|
|
void prepareDerivativeFunctionConfigurations();
|
|
|
|
/// A uniqued list of derivative function configurations.
|
|
/// - `@differentiable` and `@derivative` attribute type-checking is
|
|
/// responsible for populating derivative function configurations specified
|
|
/// in the current module.
|
|
/// - Module loading is responsible for populating derivative function
|
|
/// configurations from imported modules.
|
|
struct DerivativeFunctionConfigurationList;
|
|
DerivativeFunctionConfigurationList *DerivativeFunctionConfigs = nullptr;
|
|
|
|
public:
|
|
/// Get all derivative function configurations.
|
|
ArrayRef<AutoDiffConfig>
|
|
getDerivativeFunctionConfigurations();
|
|
|
|
/// Add the given derivative function configuration.
|
|
void addDerivativeFunctionConfiguration(const AutoDiffConfig &config);
|
|
std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
|
|
getLifetimeDependencies() const;
|
|
|
|
protected:
|
|
// If a function has a body at all, we have either a parsed body AST node or
|
|
// we have saved the end location of the unparsed body.
|
|
union {
|
|
/// This enum member is active if getBodyKind() is BodyKind::Parsed or
|
|
/// BodyKind::TypeChecked.
|
|
BodyAndFingerprint BodyAndFP;
|
|
|
|
/// This enum member is active if getBodyKind() is BodyKind::Deserialized.
|
|
StringRef BodyStringRepresentation;
|
|
|
|
/// This enum member is active if getBodyKind() == BodyKind::Synthesize.
|
|
BodySynthesizer Synthesizer;
|
|
|
|
/// The location of the function body when the body is delayed or skipped.
|
|
///
|
|
/// This enum member is active if getBodyKind() is BodyKind::Unparsed.
|
|
SourceRange BodyRange;
|
|
};
|
|
|
|
friend class ParseAbstractFunctionBodyRequest;
|
|
friend class TypeCheckFunctionBodyRequest;
|
|
friend class IsFunctionBodySkippedRequest;
|
|
friend class LifetimeDependenceInfoRequest;
|
|
|
|
CaptureInfo Captures;
|
|
|
|
/// Location of the 'async' token.
|
|
SourceLoc AsyncLoc;
|
|
|
|
/// Location of the 'throws' token.
|
|
SourceLoc ThrowsLoc;
|
|
|
|
/// The error type that is being thrown.
|
|
TypeLoc ThrownType;
|
|
|
|
struct {
|
|
unsigned NeedsNewVTableEntryComputed : 1;
|
|
unsigned NeedsNewVTableEntry : 1;
|
|
unsigned NoLifetimeDependenceInfo : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
|
|
SourceLoc NameLoc, bool Async, SourceLoc AsyncLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
TypeLoc ThrownTy,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent,
|
|
GenericParams),
|
|
ValueDecl(Kind, Parent, Name, NameLoc), BodyAndFP(), AsyncLoc(AsyncLoc),
|
|
ThrowsLoc(ThrowsLoc), ThrownType(ThrownTy) {
|
|
setBodyKind(BodyKind::None);
|
|
setBodyExpandedStatus(BodyExpandedStatus::NotExpanded);
|
|
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
|
|
Bits.AbstractFunctionDecl.Overridden = false;
|
|
Bits.AbstractFunctionDecl.Async = Async;
|
|
Bits.AbstractFunctionDecl.Throws = Throws;
|
|
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = false;
|
|
Bits.AbstractFunctionDecl.DistributedThunk = false;
|
|
}
|
|
|
|
void setBodyKind(BodyKind K) {
|
|
Bits.AbstractFunctionDecl.BodyKind = unsigned(K);
|
|
}
|
|
|
|
BodySkippedStatus getBodySkippedStatus() const {
|
|
return BodySkippedStatus(Bits.AbstractFunctionDecl.BodySkippedStatus);
|
|
}
|
|
|
|
void setBodySkippedStatus(BodySkippedStatus status) {
|
|
Bits.AbstractFunctionDecl.BodySkippedStatus = unsigned(status);
|
|
}
|
|
|
|
BodyExpandedStatus getBodyExpandedStatus() const {
|
|
return BodyExpandedStatus(Bits.AbstractFunctionDecl.BodyExpandedStatus);
|
|
}
|
|
|
|
void setBodyExpandedStatus(BodyExpandedStatus status) {
|
|
Bits.AbstractFunctionDecl.BodyExpandedStatus = unsigned(status);
|
|
}
|
|
|
|
void setSILSynthesizeKind(SILSynthesizeKind K) {
|
|
Bits.AbstractFunctionDecl.SILSynthesizeKind = unsigned(K);
|
|
}
|
|
|
|
SILSynthesizeKind getSILSynthesizeKind() const {
|
|
return SILSynthesizeKind(Bits.AbstractFunctionDecl.SILSynthesizeKind);
|
|
}
|
|
|
|
public:
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseIdentifier().str() : "_";
|
|
}
|
|
|
|
/// Should this declaration be treated as if annotated with transparent
|
|
/// attribute.
|
|
bool isTransparent() const;
|
|
|
|
// Expose our import as member status
|
|
ImportAsMemberStatus getImportAsMemberStatus() const {
|
|
return ImportAsMemberStatus(Bits.AbstractFunctionDecl.IAMStatus);
|
|
}
|
|
bool isImportAsMember() const {
|
|
return getImportAsMemberStatus().isImportAsMember();
|
|
}
|
|
bool isImportAsInstanceMember() const {
|
|
return getImportAsMemberStatus().isInstance();
|
|
}
|
|
bool isImportAsStaticMember() const {
|
|
return getImportAsMemberStatus().isStatic();
|
|
}
|
|
uint8_t getSelfIndex() const {
|
|
return getImportAsMemberStatus().getSelfIndex();
|
|
}
|
|
|
|
void setImportAsStaticMember() {
|
|
auto newValue = getImportAsMemberStatus();
|
|
newValue.setStatic();
|
|
Bits.AbstractFunctionDecl.IAMStatus = newValue.getRawValue();
|
|
}
|
|
void setSelfIndex(uint8_t idx) {
|
|
auto newValue = getImportAsMemberStatus();
|
|
newValue.setSelfIndex(idx);
|
|
Bits.AbstractFunctionDecl.IAMStatus = newValue.getRawValue();
|
|
}
|
|
|
|
/// Retrieve the location of the 'async' keyword, if present.
|
|
SourceLoc getAsyncLoc() const { return AsyncLoc; }
|
|
|
|
/// Retrieve the location of the 'throws' keyword, if present.
|
|
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
|
|
|
|
/// Returns true if the function is marked as `async`. The
|
|
/// type of the function will be `async` as well.
|
|
bool hasAsync() const { return Bits.AbstractFunctionDecl.Async; }
|
|
|
|
/// Determine whether the given function is concurrent.
|
|
///
|
|
/// A function is concurrent if it has the @Sendable attribute.
|
|
bool isSendable() const;
|
|
|
|
/// Returns true if the function is a suitable 'async' context.
|
|
///
|
|
/// Functions that are an 'async' context can make calls to 'async' functions.
|
|
bool isAsyncContext() const {
|
|
return hasAsync();
|
|
}
|
|
|
|
/// Returns true if the function body throws.
|
|
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }
|
|
|
|
/// Retrieves the type representation for the thrown type.
|
|
TypeRepr *getThrownTypeRepr() const {
|
|
return ThrownType.getTypeRepr();
|
|
}
|
|
|
|
/// Retrieves the thrown interface type.
|
|
Type getThrownInterfaceType() const;
|
|
|
|
/// Returns the thrown interface type of this function if it has already been
|
|
/// computed, otherwise `nullopt`. This should only be used for dumping.
|
|
std::optional<Type> getCachedThrownInterfaceType() const;
|
|
|
|
/// Retrieve the "effective" thrown interface type, or std::nullopt if
|
|
/// this function cannot throw.
|
|
///
|
|
/// Functions with untyped throws will produce "any Error", functions that
|
|
/// cannot throw or are specified to throw "Never" will return std::nullopt.
|
|
std::optional<Type> getEffectiveThrownErrorType() const;
|
|
|
|
/// Returns if the function throws or is async.
|
|
bool hasEffect(EffectKind kind) const;
|
|
|
|
/// Returns if the function is 'rethrows' or 'reasync'.
|
|
bool hasPolymorphicEffect(EffectKind kind) const;
|
|
|
|
/// Is this a thunk function used to access a distributed method
|
|
/// or computed property outside of its actor isolation context?
|
|
bool isDistributedThunk() const {
|
|
return Bits.AbstractFunctionDecl.DistributedThunk;
|
|
}
|
|
|
|
void setDistributedThunk(bool isThunk) {
|
|
Bits.AbstractFunctionDecl.DistributedThunk = isThunk;
|
|
}
|
|
|
|
/// For a 'distributed' target (func or computed property),
|
|
/// get the 'thunk' responsible for performing the 'remoteCall'.
|
|
///
|
|
/// \return the synthesized thunk, or null if the base of the call has
|
|
/// diagnosed errors during type checking.
|
|
FuncDecl *getDistributedThunk() const;
|
|
|
|
PolymorphicEffectKind getPolymorphicEffectKind(EffectKind kind) const;
|
|
|
|
// FIXME: Hack that provides names with keyword arguments for accessors.
|
|
DeclName getEffectiveFullName() const;
|
|
|
|
/// Returns true if the function has a body written in the source file.
|
|
///
|
|
/// Note that a true return value does not imply that the body was actually
|
|
/// parsed.
|
|
bool hasBody() const;
|
|
|
|
/// Returns a boolean value indicating whether the body, if any, contains
|
|
/// an explicit `return` statement.
|
|
///
|
|
/// \returns `true` if the body contains an explicit `return` statement,
|
|
/// `false` otherwise.
|
|
bool bodyHasExplicitReturnStmt() const;
|
|
|
|
/// Finds occurrences of explicit `return` statements within the body, if any.
|
|
///
|
|
/// \param results An out container to which the results are added.
|
|
void getExplicitReturnStmts(SmallVectorImpl<ReturnStmt *> &results) const;
|
|
|
|
/// Returns true if the text of this function's body can be retrieved either
|
|
/// by extracting the text from the source buffer or reading the inlinable
|
|
/// body from a deserialized swiftmodule.
|
|
bool hasInlinableBodyText() const;
|
|
|
|
/// Returns the function body, if it was parsed, or nullptr otherwise.
|
|
///
|
|
/// Note that a null return value does not imply that the source code did not
|
|
/// have a body for this function.
|
|
///
|
|
/// \sa hasBody()
|
|
BraceStmt *getBody(bool canSynthesize = true) const;
|
|
|
|
/// Retrieve the body after macro expansion, which might also have been
|
|
/// type-checked.
|
|
BraceStmt *getMacroExpandedBody() const;
|
|
|
|
/// Retrieve the type-checked body of the given function, or \c nullptr if
|
|
/// there's no body available.
|
|
BraceStmt *getTypecheckedBody() const;
|
|
|
|
/// Set a new body for the function.
|
|
void setBody(BraceStmt *S, BodyKind NewBodyKind);
|
|
|
|
/// Note that parsing for the body was delayed.
|
|
void setBodyDelayed(SourceRange bodyRange) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
assert(bodyRange.isValid());
|
|
BodyRange = bodyRange;
|
|
setBodyKind(BodyKind::Unparsed);
|
|
}
|
|
|
|
void setBodyToBeReparsed(SourceRange bodyRange);
|
|
|
|
/// Provide the parsed body for the function.
|
|
void setBodyParsed(BraceStmt *S,
|
|
std::optional<Fingerprint> fp = std::nullopt) {
|
|
setBody(S, BodyKind::Parsed);
|
|
BodyAndFP.setFingerprint(fp);
|
|
}
|
|
|
|
/// Was there a nested type declaration detected when parsing this
|
|
/// function was skipped?
|
|
bool hasNestedTypeDeclarations() const {
|
|
return Bits.AbstractFunctionDecl.HasNestedTypeDeclarations;
|
|
}
|
|
|
|
void setHasNestedTypeDeclarations(bool value) {
|
|
Bits.AbstractFunctionDecl.HasNestedTypeDeclarations = value;
|
|
}
|
|
|
|
/// Note that parsing for the body was delayed.
|
|
///
|
|
/// The function should return the body statement and a flag indicating
|
|
/// whether that body is already type-checked.
|
|
void setBodySynthesizer(
|
|
std::pair<BraceStmt *, bool> (* fn)(AbstractFunctionDecl *, void *),
|
|
void *context = nullptr) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
Synthesizer = {fn, context};
|
|
setBodyKind(BodyKind::Synthesize);
|
|
}
|
|
|
|
/// Note that this is a memberwise initializer and thus the body will be
|
|
/// generated by SILGen.
|
|
void setIsMemberwiseInitializer() {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
assert(isa<ConstructorDecl>(this));
|
|
setBodyKind(BodyKind::SILSynthesize);
|
|
setSILSynthesizeKind(SILSynthesizeKind::MemberwiseInitializer);
|
|
}
|
|
|
|
/// Mark that the body should be filled in to be a factory method for creating
|
|
/// a distributed actor.
|
|
void setDistributedActorFactory() {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
assert(isa<FuncDecl>(this));
|
|
setBodyKind(BodyKind::SILSynthesize);
|
|
setSILSynthesizeKind(SILSynthesizeKind::DistributedActorFactory);
|
|
}
|
|
|
|
/// Gets the body of this function, stripping the unused portions of #if
|
|
/// configs inside the body. If this function was not deserialized from a
|
|
/// .swiftmodule, this body is reconstructed from the original
|
|
/// source buffer.
|
|
StringRef getInlinableBodyText(SmallVectorImpl<char> &scratch) const;
|
|
|
|
void setBodyStringRepresentation(StringRef body) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
setBodyKind(BodyKind::Deserialized);
|
|
BodyStringRepresentation = body;
|
|
}
|
|
|
|
bool isBodyTypeChecked() const {
|
|
return getBodyKind() == BodyKind::TypeChecked;
|
|
}
|
|
|
|
bool isBodySILSynthesize() const {
|
|
return getBodyKind() == BodyKind::SILSynthesize;
|
|
}
|
|
|
|
/// Indicates whether the body of this function is skipped during
|
|
/// typechecking.
|
|
bool isBodySkipped() const;
|
|
|
|
bool isMemberwiseInitializer() const {
|
|
return getBodyKind() == BodyKind::SILSynthesize
|
|
&& getSILSynthesizeKind() == SILSynthesizeKind::MemberwiseInitializer;
|
|
}
|
|
|
|
/// Determines whether this function represents a distributed actor
|
|
/// initialization factory. Such functions do not have a body that is
|
|
/// representable in the AST, so it must be synthesized during SILGen.
|
|
bool isDistributedActorFactory() const {
|
|
return getBodyKind() == BodyKind::SILSynthesize &&
|
|
getSILSynthesizeKind() == SILSynthesizeKind::DistributedActorFactory;
|
|
}
|
|
|
|
/// Return a vector of distributed requirements that this distributed method
|
|
/// is implementing.
|
|
///
|
|
/// If the method is witness to multiple requirements this is incorrect and
|
|
/// should be diagnosed during type-checking as it may make remoteCalls
|
|
/// ambiguous.
|
|
llvm::ArrayRef<ValueDecl *>
|
|
getDistributedMethodWitnessedProtocolRequirements() const;
|
|
|
|
/// Determines whether this function is a 'remoteCall' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedActorSystem' protocol.
|
|
bool isDistributedActorSystemRemoteCall(bool isVoidReturn) const;
|
|
|
|
/// Determines whether this function is a 'makeInvocationEncoder' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedActorSystem' protocol.
|
|
bool isDistributedActorSystemMakeInvocationEncoder() const;
|
|
|
|
/// Determines if this function is a 'recordGenericSubstitution' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationEncoder' protocol.
|
|
bool isDistributedTargetInvocationEncoderRecordGenericSubstitution() const;
|
|
|
|
/// Determines if this function is a 'recordArgument' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationEncoder' protocol.
|
|
bool isDistributedTargetInvocationEncoderRecordArgument() const;
|
|
|
|
/// Determines if this function is a 'recordReturnType' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationEncoder' protocol.
|
|
bool isDistributedTargetInvocationEncoderRecordReturnType() const;
|
|
|
|
/// Determines if this function is a 'recordErrorType' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationEncoder' protocol.
|
|
bool isDistributedTargetInvocationEncoderRecordErrorType() const;
|
|
|
|
/// Determines if this function is a 'decodeNextArgument' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationDecoder' protocol.
|
|
bool isDistributedTargetInvocationDecoderDecodeNextArgument() const;
|
|
|
|
/// Determines if this function is a 'onReturn' function,
|
|
/// which is used as ad-hoc protocol requirement by the
|
|
/// 'DistributedTargetInvocationResultHandler' protocol.
|
|
bool isDistributedTargetInvocationResultHandlerOnReturn() const;
|
|
|
|
/// Determines whether this declaration is a witness to a
|
|
/// protocol requirement with ad-hoc `SerializationRequirement`
|
|
/// conformance.
|
|
bool isDistributedWitnessWithAdHocSerializationRequirement() const {
|
|
return isDistributedActorSystemRemoteCall(/*isVoidResult=*/false) ||
|
|
isDistributedTargetInvocationEncoderRecordArgument() ||
|
|
isDistributedTargetInvocationEncoderRecordReturnType() ||
|
|
isDistributedTargetInvocationDecoderDecodeNextArgument() ||
|
|
isDistributedTargetInvocationResultHandlerOnReturn();
|
|
}
|
|
|
|
/// For a method of a class, checks whether it will require a new entry in the
|
|
/// vtable.
|
|
bool needsNewVTableEntry() const;
|
|
|
|
/// True if the decl is a method which introduces a new witness table entry.
|
|
bool requiresNewWitnessTableEntry() const {
|
|
return getOverriddenDecls().empty();
|
|
}
|
|
|
|
public:
|
|
/// Retrieve the source range of the function body.
|
|
SourceRange getBodySourceRange() const;
|
|
|
|
/// Keep current \c getBodySourceRange() as the "original" body source range
|
|
/// iff the this method hasn't been called on this object. The current body
|
|
/// source range must be in the same buffer as the location of the declaration
|
|
/// itself.
|
|
void keepOriginalBodySourceRange();
|
|
|
|
/// Retrieve the fingerprint of the body. Note that this is not affected by
|
|
/// the body of the local functions or the members of the local types in this
|
|
/// function.
|
|
std::optional<Fingerprint> getBodyFingerprint() const;
|
|
|
|
/// Retrieve the fingerprint of the body including the local type members and
|
|
/// the local function bodies.
|
|
std::optional<Fingerprint>
|
|
getBodyFingerprintIncludingLocalTypeMembers() const;
|
|
|
|
/// Retrieve the source range of the *original* function body.
|
|
///
|
|
/// This may be different from \c getBodySourceRange() that returns the source
|
|
/// range of the *current* body. It happens when the body is parsed from other
|
|
/// source buffers for e.g. code-completion.
|
|
SourceRange getOriginalBodySourceRange() const;
|
|
|
|
/// Retrieve the source range of the function declaration name and parameter list.
|
|
SourceRange getParameterListSourceRange() const;
|
|
|
|
/// Retrieve the source range of the function declaration name, parameter list,
|
|
/// and effects. For FuncDecl, this does not include the return type.
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
CaptureInfo getCaptureInfo() const;
|
|
|
|
std::optional<CaptureInfo> getCachedCaptureInfo() const {
|
|
if (!Captures.hasBeenComputed())
|
|
return std::nullopt;
|
|
return Captures;
|
|
}
|
|
|
|
void setCaptureInfo(CaptureInfo captures) {
|
|
assert(captures.hasBeenComputed());
|
|
Captures = captures;
|
|
}
|
|
|
|
/// Retrieve the Objective-C selector that names this method.
|
|
ObjCSelector getObjCSelector(DeclName preferredName = DeclName(),
|
|
bool skipIsObjCResolution = false) const;
|
|
|
|
/// Determine whether the given method would produce an Objective-C
|
|
/// instance method.
|
|
bool isObjCInstanceMethod() const;
|
|
|
|
/// Determine whether the name of an argument is an API name by default
|
|
/// depending on the function context.
|
|
bool argumentNameIsAPIByDefault() const;
|
|
|
|
/// Retrieve the function's parameter list, not including 'self' if present.
|
|
ParameterList *getParameters() {
|
|
return Params;
|
|
}
|
|
const ParameterList *getParameters() const {
|
|
return Params;
|
|
}
|
|
|
|
void setParameters(ParameterList *Params);
|
|
|
|
bool hasImplicitSelfDecl() const {
|
|
return Bits.AbstractFunctionDecl.HasImplicitSelfDecl;
|
|
}
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Retrieve the implicit 'self' parameter for methods. Returns nullptr for
|
|
/// free functions.
|
|
const ParamDecl *getImplicitSelfDecl(bool createIfNeeded=true) const {
|
|
return const_cast<AbstractFunctionDecl*>(this)
|
|
->getImplicitSelfDecl(createIfNeeded);
|
|
}
|
|
ParamDecl *getImplicitSelfDecl(bool createIfNeeded=true);
|
|
|
|
/// Retrieve the declaration that this method overrides, if any.
|
|
AbstractFunctionDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AbstractFunctionDecl>(ValueDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Whether the declaration is later overridden in the module
|
|
///
|
|
/// Overrides are resolved during type checking; only query this field after
|
|
/// the whole module has been checked
|
|
bool isOverridden() const { return Bits.AbstractFunctionDecl.Overridden; }
|
|
|
|
/// The declaration has been overridden in the module
|
|
///
|
|
/// Resolved during type checking
|
|
void setIsOverridden() { Bits.AbstractFunctionDecl.Overridden = true; }
|
|
|
|
/// Set information about the foreign error convention used by this
|
|
/// declaration.
|
|
void setForeignErrorConvention(const ForeignErrorConvention &convention);
|
|
|
|
/// Get information about the foreign error convention used by this
|
|
/// declaration, given that it is @objc and 'throws'.
|
|
std::optional<ForeignErrorConvention> getForeignErrorConvention() const;
|
|
|
|
/// If this is a foreign C function imported as a method, get the index of
|
|
/// the foreign parameter imported as `self`. If the function is imported
|
|
/// as a static method, `-1` is returned to represent the `self` parameter
|
|
/// being dropped altogether. `None` is returned for a normal function
|
|
/// or method.
|
|
std::optional<int> getForeignFunctionAsMethodSelfParameterIndex() const;
|
|
|
|
/// Set information about the foreign async convention used by this
|
|
/// declaration.
|
|
void setForeignAsyncConvention(const ForeignAsyncConvention &convention);
|
|
|
|
/// Get information about the foreign async convention used by this
|
|
/// declaration, given that it is @objc and 'async'.
|
|
std::optional<ForeignAsyncConvention> getForeignAsyncConvention() const;
|
|
|
|
/// Whether the given DeclKind is for an AbstractFunctionDecl.
|
|
static bool isKind(DeclKind kind) {
|
|
return kind >= DeclKind::First_AbstractFunctionDecl &&
|
|
kind <= DeclKind::Last_AbstractFunctionDecl;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return isKind(D->getKind());
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the declaration is forced to be statically dispatched.
|
|
bool hasForcedStaticDispatch() const;
|
|
|
|
/// Get the type of this declaration without the Self clause.
|
|
/// Asserts if not in type context.
|
|
Type getMethodInterfaceType() const;
|
|
|
|
/// Tests if this is a function returning a DynamicSelfType, or a
|
|
/// constructor.
|
|
bool hasDynamicSelfResult() const;
|
|
|
|
/// The async function marked as the alternative to this function, if any.
|
|
AbstractFunctionDecl *getAsyncAlternative() const;
|
|
|
|
/// True if the storage can be referenced by a keypath directly.
|
|
/// Otherwise, its override must be referenced.
|
|
bool isValidKeyPathComponent() const;
|
|
|
|
/// Do we need to use resilient access patterns outside of this
|
|
/// method's resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// Do we need to use resilient access patterns when accessing this
|
|
/// method from the given module?
|
|
bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// If \p asyncAlternative is set, then compare its parameters to this
|
|
/// (presumed synchronous) function's parameters to find the index of the
|
|
/// completion handler parameter. This should be the only missing
|
|
/// parameter in \p asyncAlternative, ignoring defaulted parameters if they
|
|
/// have the same label. It must have a void-returning function type and be
|
|
/// attributed with @escaping but not @autoclosure.
|
|
///
|
|
/// Returns the last index of the parameter that looks like a completion
|
|
/// handler if \p asyncAlternative is not set (with the same conditions on
|
|
/// its type as above).
|
|
std::optional<unsigned> findPotentialCompletionHandlerParam(
|
|
const AbstractFunctionDecl *asyncAlternative = nullptr) const;
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
class OperatorDecl;
|
|
|
|
/// FuncDecl - 'func' declaration.
|
|
class FuncDecl : public AbstractFunctionDecl {
|
|
friend class AbstractFunctionDecl;
|
|
friend class SelfAccessKindRequest;
|
|
friend class IsStaticRequest;
|
|
friend class ResultTypeRequest;
|
|
|
|
SourceLoc StaticLoc; // Location of the 'static' token or invalid.
|
|
SourceLoc FuncLoc; // Location of the 'func' token.
|
|
|
|
TypeLoc FnRetType;
|
|
|
|
protected:
|
|
FuncDecl(DeclKind Kind,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Async, SourceLoc AsyncLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
TypeLoc ThrownTy,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: AbstractFunctionDecl(Kind, Parent,
|
|
Name, NameLoc,
|
|
Async, AsyncLoc,
|
|
Throws, ThrowsLoc, ThrownTy,
|
|
HasImplicitSelfDecl, GenericParams),
|
|
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
|
|
assert(!Name.getBaseName().isSpecial());
|
|
|
|
Bits.FuncDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
|
|
Bits.FuncDecl.ForcedStaticDispatch = false;
|
|
Bits.FuncDecl.SelfAccess =
|
|
static_cast<unsigned>(SelfAccessKind::NonMutating);
|
|
Bits.FuncDecl.SelfAccessComputed = false;
|
|
Bits.FuncDecl.IsStaticComputed = false;
|
|
Bits.FuncDecl.IsStatic = false;
|
|
Bits.FuncDecl.HasTopLevelLocalContextCaptures = false;
|
|
Bits.FuncDecl.HasSendingResult = false;
|
|
}
|
|
|
|
void setResultInterfaceType(Type type);
|
|
|
|
private:
|
|
static FuncDecl *createImpl(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Async, SourceLoc AsyncLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
TypeLoc ThrownTy,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent,
|
|
ClangNode ClangN);
|
|
|
|
std::optional<SelfAccessKind> getCachedSelfAccessKind() const {
|
|
if (Bits.FuncDecl.SelfAccessComputed)
|
|
return static_cast<SelfAccessKind>(Bits.FuncDecl.SelfAccess);
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<bool> getCachedIsStatic() const {
|
|
if (Bits.FuncDecl.IsStaticComputed)
|
|
return Bits.FuncDecl.IsStatic;
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
public:
|
|
/// Factory function only for use by deserialization.
|
|
static FuncDecl *createDeserialized(ASTContext &Context,
|
|
StaticSpellingKind StaticSpelling,
|
|
DeclName Name, bool Async, bool Throws,
|
|
Type ThrownType,
|
|
GenericParamList *GenericParams,
|
|
Type FnRetType, DeclContext *Parent);
|
|
|
|
static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling, SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc, bool Async,
|
|
SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc,
|
|
TypeRepr *ThrownTyR,
|
|
GenericParamList *GenericParams,
|
|
ParameterList *BodyParams, TypeRepr *ResultTyR,
|
|
DeclContext *Parent);
|
|
|
|
static FuncDecl *createImplicit(ASTContext &Context,
|
|
StaticSpellingKind StaticSpelling,
|
|
DeclName Name, SourceLoc NameLoc, bool Async,
|
|
bool Throws, Type ThrownType,
|
|
GenericParamList *GenericParams,
|
|
ParameterList *BodyParams, Type FnRetType,
|
|
DeclContext *Parent);
|
|
|
|
static FuncDecl *createImported(ASTContext &Context, SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc, bool Async,
|
|
bool Throws, Type ThrownType,
|
|
ParameterList *BodyParams,
|
|
Type FnRetType,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent, ClangNode ClangN);
|
|
|
|
bool isStatic() const;
|
|
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(Bits.FuncDecl.StaticSpelling);
|
|
}
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
void setStatic(bool IsStatic = true) {
|
|
Bits.FuncDecl.IsStaticComputed = true;
|
|
Bits.FuncDecl.IsStatic = IsStatic;
|
|
}
|
|
|
|
bool isMutating() const {
|
|
return getSelfAccessKind() == SelfAccessKind::Mutating;
|
|
}
|
|
bool isCallAsFunctionMethod() const;
|
|
|
|
bool isMainTypeMainMethod() const;
|
|
|
|
SelfAccessKind getSelfAccessKind() const;
|
|
|
|
LifetimeAnnotation getLifetimeAnnotation() const;
|
|
|
|
void setSelfAccessKind(SelfAccessKind mod) {
|
|
Bits.FuncDecl.SelfAccess = static_cast<unsigned>(mod);
|
|
Bits.FuncDecl.SelfAccessComputed = true;
|
|
}
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getFuncLoc() const { return FuncLoc; }
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() ? StaticLoc : FuncLoc;
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
TypeRepr *getResultTypeRepr() const { return FnRetType.getTypeRepr(); }
|
|
|
|
SourceRange getResultTypeSourceRange() const {
|
|
return FnRetType.getSourceRange();
|
|
}
|
|
|
|
/// Retrieve the result interface type of this function.
|
|
Type getResultInterfaceType() const;
|
|
|
|
/// Returns the result interface type of this function if it has already been
|
|
/// computed, otherwise `nullopt`. This should only be used for dumping.
|
|
std::optional<Type> getCachedResultInterfaceType() const;
|
|
|
|
/// isUnaryOperator - Determine whether this is a unary operator
|
|
/// implementation. This check is a syntactic rather than type-based check,
|
|
/// which looks at the number of parameters specified, in order to allow
|
|
/// for the definition of unary operators on tuples, as in:
|
|
///
|
|
/// prefix func + (param : (a:Int, b:Int))
|
|
///
|
|
/// This also allows the unary-operator-ness of a func decl to be determined
|
|
/// prior to type checking.
|
|
bool isUnaryOperator() const;
|
|
|
|
/// isBinaryOperator - Determine whether this is a binary operator
|
|
/// implementation. This check is a syntactic rather than type-based check,
|
|
/// which looks at the number of parameters specified, in order to allow
|
|
/// distinguishing a binary operator from a unary operator on tuples, as in:
|
|
///
|
|
/// prefix func + (_:(a:Int, b:Int)) // unary operator +(1,2)
|
|
/// infix func + (a:Int, b:Int) // binary operator 1 + 2
|
|
///
|
|
/// This also allows the binary-operator-ness of a func decl to be determined
|
|
/// prior to type checking.
|
|
bool isBinaryOperator() const;
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Get the supertype method this method overrides, if any.
|
|
FuncDecl *getOverriddenDecl() const {
|
|
return cast_or_null<FuncDecl>(AbstractFunctionDecl::getOverriddenDecl());
|
|
}
|
|
|
|
OperatorDecl *getOperatorDecl() const;
|
|
|
|
/// Returns true if the function is forced to be statically dispatched.
|
|
bool hasForcedStaticDispatch() const {
|
|
return Bits.FuncDecl.ForcedStaticDispatch;
|
|
}
|
|
void setForcedStaticDispatch(bool flag) {
|
|
Bits.FuncDecl.ForcedStaticDispatch = flag;
|
|
}
|
|
|
|
/// Returns true if this FuncDecl has a sending result... returns false
|
|
/// otherwise.
|
|
bool hasSendingResult() const { return Bits.FuncDecl.HasSendingResult; }
|
|
|
|
void setSendingResult(bool newValue = true) {
|
|
Bits.FuncDecl.HasSendingResult = newValue;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Func ||
|
|
D->getKind() == DeclKind::Accessor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the function is a defer body.
|
|
bool isDeferBody() const;
|
|
|
|
/// Perform basic checking to determine whether the @IBAction or
|
|
/// @IBSegueAction attribute can be applied to this function.
|
|
bool isPotentialIBActionTarget() const;
|
|
|
|
bool hasTopLevelLocalContextCaptures() const {
|
|
return Bits.FuncDecl.HasTopLevelLocalContextCaptures;
|
|
}
|
|
|
|
void setHasTopLevelLocalContextCaptures(bool hasCaptures=true);
|
|
};
|
|
|
|
/// This represents an accessor function, such as a getter or setter.
|
|
class AccessorDecl final : public FuncDecl {
|
|
/// Location of the accessor keyword, e.g. 'set'.
|
|
SourceLoc AccessorKeywordLoc;
|
|
|
|
AbstractStorageDecl *Storage;
|
|
|
|
AccessorDecl(SourceLoc declLoc, SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind, AbstractStorageDecl *storage,
|
|
bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
|
|
TypeLoc thrownTy, bool hasImplicitSelfDecl, DeclContext *parent)
|
|
: FuncDecl(DeclKind::Accessor, /*StaticLoc*/ SourceLoc(),
|
|
StaticSpellingKind::None, /*func loc*/ declLoc,
|
|
/*name*/ Identifier(), /*name loc*/ declLoc, async, asyncLoc,
|
|
throws, throwsLoc, thrownTy, hasImplicitSelfDecl,
|
|
/*genericParams*/ nullptr, parent),
|
|
AccessorKeywordLoc(accessorKeywordLoc), Storage(storage) {
|
|
assert(!async || (accessorKind == AccessorKind::Get || accessorKind == AccessorKind::DistributedGet)
|
|
&& "only get accessors can be async");
|
|
Bits.AccessorDecl.AccessorKind = unsigned(accessorKind);
|
|
}
|
|
|
|
static AccessorDecl *
|
|
createImpl(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind, AbstractStorageDecl *storage,
|
|
bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
|
|
TypeLoc thrownTy, DeclContext *parent, ClangNode clangNode);
|
|
|
|
std::optional<bool> getCachedIsTransparent() const {
|
|
if (Bits.AccessorDecl.IsTransparentComputed)
|
|
return Bits.AccessorDecl.IsTransparent;
|
|
return std::nullopt;
|
|
}
|
|
|
|
friend class IsAccessorTransparentRequest;
|
|
|
|
public:
|
|
static AccessorDecl *
|
|
createDeserialized(ASTContext &ctx, AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage, bool async, bool throws,
|
|
Type thrownType, Type fnRetType, DeclContext *parent);
|
|
|
|
static AccessorDecl *
|
|
create(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind, AbstractStorageDecl *storage, bool async,
|
|
SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc,
|
|
TypeLoc thrownType, ParameterList *parameterList, Type fnRetType,
|
|
DeclContext *parent, ClangNode clangNode = ClangNode());
|
|
|
|
static AccessorDecl *createImplicit(ASTContext &Context,
|
|
AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage,
|
|
bool async,
|
|
bool throws, TypeLoc thrownType,
|
|
Type fnRetType,
|
|
DeclContext *parent);
|
|
|
|
/// Create a parsed accessor.
|
|
///
|
|
/// \param paramList A parameter list for e.g \c set(newValue), or \c nullptr
|
|
/// if the accessor doesn't have any user-specified arguments.
|
|
static AccessorDecl *createParsed(ASTContext &ctx, AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
ParameterList *paramList,
|
|
SourceLoc asyncLoc, SourceLoc throwsLoc,
|
|
TypeRepr *thrownType, DeclContext *dc);
|
|
|
|
/// Retrieve the implicit parameter name for the given accessor kind (e.g
|
|
/// \c oldValue for `didSet`, `newValue` for `set`), or an empty string if
|
|
/// the kind does not have an implicit parameter name.
|
|
static StringRef implicitParameterNameFor(AccessorKind kind);
|
|
|
|
SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; }
|
|
|
|
AbstractStorageDecl *getStorage() const {
|
|
return Storage;
|
|
}
|
|
|
|
AccessorKind getAccessorKind() const {
|
|
return AccessorKind(Bits.AccessorDecl.AccessorKind);
|
|
}
|
|
|
|
bool isGetter() const { return getAccessorKind() == AccessorKind::Get; }
|
|
bool isDistributedGetter() const { return getAccessorKind() == AccessorKind::DistributedGet; }
|
|
bool isSetter() const { return getAccessorKind() == AccessorKind::Set; }
|
|
bool isAnyAddressor() const {
|
|
auto kind = getAccessorKind();
|
|
return kind == AccessorKind::Address
|
|
|| kind == AccessorKind::MutableAddress;
|
|
}
|
|
|
|
/// isGetterOrSetter - Determine whether this is specifically a getter or
|
|
/// a setter, as opposed to some other kind of accessor.
|
|
///
|
|
/// For example, only getters and setters can be exposed to Objective-C.
|
|
bool isGetterOrSetter() const { return isGetter() || isSetter(); }
|
|
|
|
bool isObservingAccessor() const {
|
|
switch (getAccessorKind()) {
|
|
#define OBSERVING_ACCESSOR(ID, KEYWORD) \
|
|
case AccessorKind::ID: return true;
|
|
#define ACCESSOR(ID) \
|
|
case AccessorKind::ID: return false;
|
|
#include "swift/AST/AccessorKinds.def"
|
|
}
|
|
llvm_unreachable("bad accessor kind");
|
|
}
|
|
|
|
bool isInitAccessor() const {
|
|
return (getAccessorKind() == AccessorKind::Init);
|
|
}
|
|
|
|
/// \returns true if this is non-mutating due to applying a 'mutating'
|
|
/// attribute. For example a "mutating set" accessor.
|
|
bool isExplicitNonMutating() const;
|
|
|
|
/// Is the accessor one of the kinds that's assumed nonmutating by default?
|
|
bool isAssumedNonMutating() const;
|
|
|
|
/// Is this accessor one of the kinds that's implicitly a coroutine?
|
|
bool isCoroutine() const {
|
|
switch (getAccessorKind()) {
|
|
#define COROUTINE_ACCESSOR(ID, KEYWORD) \
|
|
case AccessorKind::ID: return true;
|
|
#define ACCESSOR(ID) \
|
|
case AccessorKind::ID: return false;
|
|
#include "swift/AST/AccessorKinds.def"
|
|
}
|
|
llvm_unreachable("bad accessor kind");
|
|
}
|
|
|
|
bool isImplicitGetter() const {
|
|
return isGetter() && getAccessorKeywordLoc().isInvalid();
|
|
}
|
|
|
|
/// Is this accessor a "simple" didSet? A "simple" didSet does not
|
|
/// use the implicit oldValue parameter in its body or does not have
|
|
/// an explicit parameter in its parameter list.
|
|
bool isSimpleDidSet() const;
|
|
|
|
void setIsTransparent(bool transparent) {
|
|
Bits.AccessorDecl.IsTransparent = transparent;
|
|
Bits.AccessorDecl.IsTransparentComputed = 1;
|
|
}
|
|
|
|
/// A representation of the name to be displayed to users. \c getNameStr
|
|
/// for anything other than a getter or setter.
|
|
void printUserFacingName(llvm::raw_ostream &out) const;
|
|
|
|
/// If this is an init accessor, retrieve a list of instance properties
|
|
/// initialized by it.
|
|
ArrayRef<VarDecl *> getInitializedProperties() const;
|
|
/// If this is an init accessor, retrieve a list of instance properties
|
|
/// accessed by it.
|
|
ArrayRef<VarDecl *> getAccessedProperties() const;
|
|
|
|
/// Whether this accessor should have a body. Note that this will be true
|
|
/// even when it does not have one _yet_.
|
|
bool doesAccessorHaveBody() const;
|
|
|
|
/// Whether this accessor is a protocol requirement for which a default
|
|
/// implementation must be provided for back-deployment. For example, read2
|
|
/// and modify2 requirements with early enough availability.
|
|
bool isRequirementWithSynthesizedDefaultImplementation() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Accessor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
inline AccessorDecl *
|
|
AbstractStorageDecl::AccessorRecord::getAccessor(AccessorKind kind) const {
|
|
if (auto optIndex = AccessorIndices[unsigned(kind)]) {
|
|
auto accessor = getAllAccessors()[optIndex - 1];
|
|
assert(accessor && accessor->getAccessorKind() == kind);
|
|
return accessor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/// This represents a 'case' declaration in an 'enum', which may declare
|
|
/// one or more individual comma-separated EnumElementDecls.
|
|
class EnumCaseDecl final : public Decl,
|
|
private llvm::TrailingObjects<EnumCaseDecl, EnumElementDecl *> {
|
|
friend TrailingObjects;
|
|
friend class Decl;
|
|
SourceLoc CaseLoc;
|
|
|
|
EnumCaseDecl(SourceLoc CaseLoc,
|
|
ArrayRef<EnumElementDecl *> Elements,
|
|
DeclContext *DC)
|
|
: Decl(DeclKind::EnumCase, DC),
|
|
CaseLoc(CaseLoc)
|
|
{
|
|
Bits.EnumCaseDecl.NumElements = Elements.size();
|
|
std::uninitialized_copy(Elements.begin(), Elements.end(),
|
|
getTrailingObjects<EnumElementDecl *>());
|
|
}
|
|
SourceLoc getLocFromSource() const { return CaseLoc; }
|
|
|
|
public:
|
|
static EnumCaseDecl *create(SourceLoc CaseLoc,
|
|
ArrayRef<EnumElementDecl*> Elements,
|
|
DeclContext *DC);
|
|
|
|
/// Get the list of elements declared in this case.
|
|
ArrayRef<EnumElementDecl *> getElements() const {
|
|
return {getTrailingObjects<EnumElementDecl *>(),
|
|
static_cast<size_t>(Bits.EnumCaseDecl.NumElements)};
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Returns the first of the member elements or null if there are no elements.
|
|
/// The attributes written with an EnumCaseDecl will be attached to each of
|
|
/// the elements instead so inspecting the attributes of the first element is
|
|
/// often useful.
|
|
EnumElementDecl *getFirstElement() const {
|
|
auto elements = getElements();
|
|
return elements.empty() ? nullptr : elements.front();
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumCase;
|
|
}
|
|
};
|
|
|
|
/// This represents a single case of an 'enum' declaration.
|
|
///
|
|
/// For example, the X, Y, and Z in this enum:
|
|
///
|
|
/// \code
|
|
/// enum V {
|
|
/// case X(Int), Y(Int)
|
|
/// case Z
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// The type of an EnumElementDecl is always the EnumType for the containing
|
|
/// enum. EnumElementDecls are represented in the AST as members of their
|
|
/// parent EnumDecl, although syntactically they are subordinate to the
|
|
/// EnumCaseDecl.
|
|
class EnumElementDecl : public DeclContext, public ValueDecl {
|
|
friend class EnumRawValuesRequest;
|
|
friend class LifetimeDependenceInfoRequest;
|
|
|
|
/// This is the type specified with the enum element, for
|
|
/// example 'Int' in 'case Y(Int)'. This is null if there is no type
|
|
/// associated with this element, as in 'case Z' or in all elements of enum
|
|
/// definitions.
|
|
ParameterList *Params;
|
|
|
|
SourceLoc EqualsLoc;
|
|
|
|
/// The raw value literal for the enum element, or null.
|
|
LiteralExpr *RawValueExpr;
|
|
|
|
protected:
|
|
struct {
|
|
unsigned NoLifetimeDependenceInfo : 1;
|
|
} LazySemanticInfo = {};
|
|
|
|
public:
|
|
EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name,
|
|
ParameterList *Params,
|
|
SourceLoc EqualsLoc,
|
|
LiteralExpr *RawValueExpr,
|
|
DeclContext *DC);
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseIdentifier().str() : "_";
|
|
}
|
|
|
|
/// Retrieve the payload type for the enum element, which is a tuple of the
|
|
/// associated values, or null if there are no associated values.
|
|
Type getPayloadInterfaceType() const;
|
|
|
|
/// Retrieve the parameters of the implicit case constructor for the enum
|
|
/// element.
|
|
ArrayRef<AnyFunctionType::Param> getCaseConstructorParams() const;
|
|
|
|
void setParameterList(ParameterList *params);
|
|
ParameterList *getParameterList() const { return Params; }
|
|
|
|
/// Retrieves a fully typechecked raw value expression associated
|
|
/// with this enum element, if it exists.
|
|
LiteralExpr *getRawValueExpr() const;
|
|
|
|
/// Retrieves a "structurally" checked raw value expression associated
|
|
/// with this enum element, if it exists.
|
|
///
|
|
/// The structural raw value may or may not have a type set, but it is
|
|
/// guaranteed to be suitable for retrieving any non-semantic information
|
|
/// like digit text for an integral raw value or user text for a string raw value.
|
|
LiteralExpr *getStructuralRawValueExpr() const;
|
|
|
|
/// Reset the raw value expression.
|
|
void setRawValueExpr(LiteralExpr *e);
|
|
|
|
/// Return the containing EnumDecl.
|
|
EnumDecl *getParentEnum() const {
|
|
return cast<EnumDecl>(getDeclContext());
|
|
}
|
|
|
|
/// Return the containing EnumCaseDecl.
|
|
EnumCaseDecl *getParentCase() const;
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return getNameLoc();
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
bool hasAssociatedValues() const {
|
|
return getParameterList() != nullptr;
|
|
}
|
|
|
|
/// True if the case is marked 'indirect'.
|
|
bool isIndirect() const {
|
|
return getAttrs().hasAttribute<IndirectAttr>();
|
|
}
|
|
|
|
/// Do not call this!
|
|
/// It exists to let the AST walkers get the raw value without forcing a request.
|
|
LiteralExpr *getRawValueUnchecked() const { return RawValueExpr; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumElement;
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
inline SourceRange EnumCaseDecl::getSourceRange() const {
|
|
auto subRange = getElements().back()->getSourceRange();
|
|
if (subRange.isValid())
|
|
return {CaseLoc, subRange.End};
|
|
return {};
|
|
}
|
|
|
|
/// Describes the kind of initializer.
|
|
enum class CtorInitializerKind {
|
|
/// A designated initializer is an initializer responsible for initializing
|
|
/// the stored properties of the current class and chaining to a superclass's
|
|
/// designated initializer (for non-root classes).
|
|
///
|
|
/// Designated initializers are never inherited.
|
|
Designated,
|
|
|
|
/// A convenience initializer is an initializer that initializes a complete
|
|
/// object by delegating to another initializer (eventually reaching a
|
|
/// designated initializer).
|
|
///
|
|
/// Convenience initializers are inherited into subclasses that override
|
|
/// all of their superclass's designated initializers.
|
|
Convenience,
|
|
|
|
/// A convenience factory initializer is a convenience initializer introduced
|
|
/// by an imported Objective-C factory method.
|
|
///
|
|
/// Convenience factory initializers cannot be expressed directly in
|
|
/// Swift; rather, they are produced by the Clang importer when importing
|
|
/// an instancetype factory method from Objective-C.
|
|
ConvenienceFactory,
|
|
|
|
/// A factory initializer is an initializer that is neither designated nor
|
|
/// convenience: it can be used to create an object of the given type, but
|
|
/// cannot be chained to via "super.init" nor is it inherited.
|
|
///
|
|
/// A factory initializer is written with a return type of the class name
|
|
/// itself. FIXME: However, this is only a presentation form, and at present
|
|
/// the only factory initializers are produced by importing an Objective-C
|
|
/// factory method that does not return instancetype.
|
|
///
|
|
/// FIXME: Arguably, structs and enums only have factory initializers, and
|
|
/// using designated initializers for them is a misnomer.
|
|
Factory
|
|
};
|
|
|
|
/// Specifies the kind of initialization call performed within the body
|
|
/// of the constructor, e.g., self.init or super.init.
|
|
enum class BodyInitKind {
|
|
/// There are no calls to self.init or super.init.
|
|
None,
|
|
/// There is a call to self.init, which delegates to another (peer)
|
|
/// initializer.
|
|
Delegating,
|
|
/// There is a call to super.init, which chains to a superclass initializer.
|
|
Chained,
|
|
/// There are no calls to self.init or super.init explicitly in the body of
|
|
/// the constructor, but a 'super.init' call will be implicitly added
|
|
/// by semantic analysis.
|
|
ImplicitChained
|
|
};
|
|
|
|
struct BodyInitKindAndExpr {
|
|
BodyInitKind initKind;
|
|
ApplyExpr *initExpr;
|
|
|
|
BodyInitKindAndExpr() : initKind(BodyInitKind::None), initExpr(nullptr) {}
|
|
|
|
BodyInitKindAndExpr(BodyInitKind initKind, ApplyExpr *initExpr)
|
|
: initKind(initKind), initExpr(initExpr) {}
|
|
|
|
friend bool operator==(BodyInitKindAndExpr lhs, BodyInitKindAndExpr rhs) {
|
|
return (lhs.initKind == rhs.initKind &&
|
|
lhs.initExpr == rhs.initExpr);
|
|
}
|
|
};
|
|
|
|
/// ConstructorDecl - Declares a constructor for a type. For example:
|
|
///
|
|
/// \code
|
|
/// struct X {
|
|
/// var x : Int
|
|
/// init(i : Int) {
|
|
/// x = i
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
class ConstructorDecl : public AbstractFunctionDecl {
|
|
/// The location of the '!' or '?' for a failable initializer.
|
|
SourceLoc FailabilityLoc;
|
|
|
|
ParamDecl *SelfDecl;
|
|
|
|
/// The interface type of the initializing constructor.
|
|
Type InitializerInterfaceType;
|
|
|
|
/// The typechecked call to super.init expression, which needs to be
|
|
/// inserted at the end of the initializer by SILGen.
|
|
Expr *CallToSuperInit = nullptr;
|
|
|
|
public:
|
|
ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
|
|
bool Failable, SourceLoc FailabilityLoc,
|
|
bool Async, SourceLoc AsyncLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
TypeLoc thrownTy,
|
|
ParameterList *BodyParams,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent);
|
|
|
|
static ConstructorDecl *
|
|
createImported(ASTContext &ctx, ClangNode clangNode, DeclName name,
|
|
SourceLoc constructorLoc,
|
|
bool failable, SourceLoc failabilityLoc,
|
|
bool async, SourceLoc asyncLoc,
|
|
bool throws, SourceLoc throwsLoc,
|
|
Type thrownTy,
|
|
ParameterList *bodyParams, GenericParamList *genericParams,
|
|
DeclContext *parent);
|
|
|
|
SourceLoc getConstructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getConstructorLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Get the interface type of the constructed object.
|
|
Type getResultInterfaceType() const;
|
|
|
|
/// Get the interface type of the initializing constructor.
|
|
Type getInitializerInterfaceType();
|
|
|
|
/// Get the typechecked call to super.init expression, which needs to be
|
|
/// inserted at the end of the initializer by SILGen.
|
|
Expr *getSuperInitCall() { return CallToSuperInit; }
|
|
void setSuperInitCall(Expr *CallExpr) { CallToSuperInit = CallExpr; }
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage() { return &SelfDecl; }
|
|
|
|
/// Determine whether the body of this constructor contains any delegating
|
|
/// or superclass initializations (\c self.init or \c super.init,
|
|
/// respectively) within its body.
|
|
BodyInitKindAndExpr getDelegatingOrChainedInitKind() const;
|
|
void clearCachedDelegatingOrChainedInitKind();
|
|
|
|
/// Whether this constructor is required.
|
|
bool isRequired() const {
|
|
return getAttrs().hasAttribute<RequiredAttr>();
|
|
}
|
|
|
|
/// Determine the kind of initializer this is.
|
|
CtorInitializerKind getInitKind() const;
|
|
|
|
/// Whether this is a designated initializer.
|
|
bool isDesignatedInit() const {
|
|
return getInitKind() == CtorInitializerKind::Designated;
|
|
}
|
|
|
|
/// Whether this is a convenience initializer.
|
|
bool isConvenienceInit() const {
|
|
return getInitKind() == CtorInitializerKind::Convenience ||
|
|
getInitKind() == CtorInitializerKind::ConvenienceFactory;
|
|
}
|
|
|
|
/// Whether this is a factory initializer.
|
|
bool isFactoryInit() const {
|
|
switch (getInitKind()) {
|
|
case CtorInitializerKind::Designated:
|
|
case CtorInitializerKind::Convenience:
|
|
return false;
|
|
|
|
case CtorInitializerKind::Factory:
|
|
case CtorInitializerKind::ConvenienceFactory:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad CtorInitializerKind");
|
|
}
|
|
|
|
/// Determine whether this initializer is inheritable.
|
|
bool isInheritable() const {
|
|
switch (getInitKind()) {
|
|
case CtorInitializerKind::Designated:
|
|
case CtorInitializerKind::Factory:
|
|
return false;
|
|
|
|
case CtorInitializerKind::Convenience:
|
|
case CtorInitializerKind::ConvenienceFactory:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad CtorInitializerKind");
|
|
}
|
|
|
|
/// Determine if this is a failable initializer.
|
|
bool isFailable() const {
|
|
return Bits.ConstructorDecl.Failable;
|
|
}
|
|
|
|
/// Retrieve the location of the '!' or '?' in a failable initializer.
|
|
SourceLoc getFailabilityLoc() const { return FailabilityLoc; }
|
|
|
|
/// Whether the implementation of this method is a stub that traps at runtime.
|
|
bool hasStubImplementation() const {
|
|
return Bits.ConstructorDecl.HasStubImplementation;
|
|
}
|
|
|
|
/// Set whether the implementation of this method is a stub that
|
|
/// traps at runtime.
|
|
void setStubImplementation(bool stub) {
|
|
Bits.ConstructorDecl.HasStubImplementation = stub;
|
|
}
|
|
|
|
ConstructorDecl *getOverriddenDecl() const {
|
|
return cast_or_null<ConstructorDecl>(
|
|
AbstractFunctionDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Determine whether this initializer falls into the special case for
|
|
/// Objective-C initializers with selectors longer than "init", e.g.,
|
|
/// \c initForMemory.
|
|
///
|
|
/// In such cases, one can write the Swift initializer
|
|
/// with a single parameter of type '()', e.g,
|
|
///
|
|
/// \code
|
|
/// @objc init(forMemory: ())
|
|
/// \endcode
|
|
bool isObjCZeroParameterWithLongSelector() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Constructor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// DestructorDecl - Declares a destructor for a type. For example:
|
|
///
|
|
/// \code
|
|
/// struct X {
|
|
/// var fd : Int
|
|
/// deinit {
|
|
/// close(fd)
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
class DestructorDecl : public AbstractFunctionDecl {
|
|
ParamDecl *SelfDecl;
|
|
|
|
public:
|
|
DestructorDecl(SourceLoc DestructorLoc, DeclContext *Parent);
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage() { return &SelfDecl; }
|
|
|
|
SourceLoc getDestructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getDestructorLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Retrieve the Objective-C selector for destructors.
|
|
ObjCSelector getObjCSelector() const;
|
|
|
|
/// Retrieves destructor decl from the superclass, or nil if there is no
|
|
/// superclass
|
|
DestructorDecl *getSuperDeinit() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Destructor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// Declares a precedence group. For example:
|
|
///
|
|
/// \code
|
|
/// precedencegroup MultiplicativePrecedence {
|
|
/// associativity: right
|
|
/// higherThan: AdditivePrecedence
|
|
/// }
|
|
/// \endcode
|
|
class PrecedenceGroupDecl : public Decl {
|
|
public:
|
|
struct Relation {
|
|
SourceLoc NameLoc;
|
|
Identifier Name;
|
|
PrecedenceGroupDecl *Group;
|
|
};
|
|
|
|
private:
|
|
SourceLoc PrecedenceGroupLoc, NameLoc, LBraceLoc, RBraceLoc;
|
|
SourceLoc AssociativityKeywordLoc, AssociativityValueLoc;
|
|
SourceLoc AssignmentKeywordLoc, AssignmentValueLoc;
|
|
SourceLoc HigherThanLoc, LowerThanLoc;
|
|
Identifier Name;
|
|
unsigned NumHigherThan, NumLowerThan;
|
|
// Tail-allocated array of Relations
|
|
|
|
Relation *getHigherThanBuffer() {
|
|
return reinterpret_cast<Relation*>(this + 1);
|
|
}
|
|
const Relation *getHigherThanBuffer() const {
|
|
return reinterpret_cast<const Relation*>(this + 1);
|
|
}
|
|
Relation *getLowerThanBuffer() {
|
|
return getHigherThanBuffer() + NumHigherThan;
|
|
}
|
|
const Relation *getLowerThanBuffer() const {
|
|
return getHigherThanBuffer() + NumHigherThan;
|
|
}
|
|
|
|
PrecedenceGroupDecl(DeclContext *DC,
|
|
SourceLoc precedenceGroupLoc,
|
|
SourceLoc nameLoc, Identifier name,
|
|
SourceLoc lbraceLoc,
|
|
SourceLoc associativityKeywordLoc,
|
|
SourceLoc associativityValueLoc,
|
|
Associativity associativity,
|
|
SourceLoc assignmentKeywordLoc,
|
|
SourceLoc assignmentValueLoc,
|
|
bool isAssignment,
|
|
SourceLoc higherThanLoc, ArrayRef<Relation> higherThan,
|
|
SourceLoc lowerThanLoc, ArrayRef<Relation> lowerThan,
|
|
SourceLoc rbraceLoc);
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
public:
|
|
static PrecedenceGroupDecl *create(DeclContext *dc,
|
|
SourceLoc precedenceGroupLoc,
|
|
SourceLoc nameLoc,
|
|
Identifier name,
|
|
SourceLoc lbraceLoc,
|
|
SourceLoc associativityKeywordLoc,
|
|
SourceLoc associativityValueLoc,
|
|
Associativity associativity,
|
|
SourceLoc assignmentKeywordLoc,
|
|
SourceLoc assignmentValueLoc,
|
|
bool isAssignment,
|
|
SourceLoc higherThanLoc,
|
|
ArrayRef<Relation> higherThan,
|
|
SourceLoc lowerThanLoc,
|
|
ArrayRef<Relation> lowerThan,
|
|
SourceLoc rbraceLoc);
|
|
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { PrecedenceGroupLoc, RBraceLoc };
|
|
}
|
|
|
|
/// Return the location of 'precedencegroup' in:
|
|
/// precedencegroup MultiplicativePrecedence { ... }
|
|
SourceLoc getPrecedenceGroupLoc() const { return PrecedenceGroupLoc; }
|
|
|
|
/// Return the location of 'MultiplicativePrecedence' in:
|
|
/// precedencegroup MultiplicativePrecedence { ... }
|
|
SourceLoc getNameLoc() const {
|
|
return NameLoc;
|
|
}
|
|
|
|
Identifier getName() const {
|
|
return Name;
|
|
}
|
|
|
|
// This is needed to allow templated code to work with both ValueDecls and
|
|
// PrecedenceGroupDecls.
|
|
DeclBaseName getBaseName() const { return Name; }
|
|
|
|
SourceLoc getLBraceLoc() const { return LBraceLoc; }
|
|
SourceLoc getRBraceLoc() const { return RBraceLoc; }
|
|
|
|
bool isAssociativityImplicit() const {
|
|
return AssociativityKeywordLoc.isInvalid();
|
|
}
|
|
|
|
/// Return the location of 'associativity' in:
|
|
/// associativity: left
|
|
SourceLoc getAssociativityKeywordLoc() const {
|
|
return AssociativityKeywordLoc;
|
|
}
|
|
|
|
/// Return the location of 'right' in:
|
|
/// associativity: right
|
|
SourceLoc getAssociativityValueLoc() const {
|
|
return AssociativityValueLoc;
|
|
}
|
|
|
|
Associativity getAssociativity() const {
|
|
return Associativity(Bits.PrecedenceGroupDecl.Associativity);
|
|
}
|
|
bool isLeftAssociative() const {
|
|
return getAssociativity() == Associativity::Left;
|
|
}
|
|
bool isRightAssociative() const {
|
|
return getAssociativity() == Associativity::Right;
|
|
}
|
|
bool isNonAssociative() const {
|
|
return getAssociativity() == Associativity::None;
|
|
}
|
|
|
|
bool isAssignmentImplicit() const {
|
|
return AssignmentKeywordLoc.isInvalid();
|
|
}
|
|
|
|
/// Return the location of 'assignment' in:
|
|
/// assignment: true
|
|
SourceLoc getAssignmentKeywordLoc() const {
|
|
return AssignmentKeywordLoc;
|
|
}
|
|
|
|
/// Return the location of 'assignment' in:
|
|
/// assignment: true
|
|
SourceLoc getAssignmentValueLoc() const {
|
|
return AssignmentValueLoc;
|
|
}
|
|
|
|
bool isAssignment() const {
|
|
return Bits.PrecedenceGroupDecl.IsAssignment;
|
|
}
|
|
|
|
bool isHigherThanImplicit() const {
|
|
return HigherThanLoc.isInvalid();
|
|
}
|
|
|
|
/// Return the location of 'higherThan' in:
|
|
/// higherThan: AdditivePrecedence
|
|
SourceLoc getHigherThanLoc() const {
|
|
return HigherThanLoc;
|
|
}
|
|
|
|
/// Retrieve the array of \c Relation objects containing those precedence
|
|
/// groups with higher precedence than this precedence group.
|
|
///
|
|
/// The elements of this array may be invalid, in which case they will have
|
|
/// null \c PrecedenceGroupDecl elements.
|
|
ArrayRef<Relation> getHigherThan() const {
|
|
return { getHigherThanBuffer(), NumHigherThan };
|
|
}
|
|
MutableArrayRef<Relation> getMutableHigherThan() {
|
|
return { getHigherThanBuffer(), NumHigherThan };
|
|
}
|
|
|
|
bool isLowerThanImplicit() const {
|
|
return LowerThanLoc.isInvalid();
|
|
}
|
|
|
|
/// Return the location of 'lowerThan' in:
|
|
/// lowerThan: MultiplicativePrecedence
|
|
SourceLoc getLowerThanLoc() const {
|
|
return LowerThanLoc;
|
|
}
|
|
|
|
/// Retrieve the array of \c Relation objects containing those precedence
|
|
/// groups with lower precedence than this precedence group.
|
|
///
|
|
/// The elements of this array may be invalid, in which case they will have
|
|
/// null \c PrecedenceGroupDecl elements.
|
|
ArrayRef<Relation> getLowerThan() const {
|
|
return { getLowerThanBuffer(), NumLowerThan };
|
|
}
|
|
MutableArrayRef<Relation> getMutableLowerThan() {
|
|
return { getLowerThanBuffer(), NumLowerThan };
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PrecedenceGroup;
|
|
}
|
|
};
|
|
|
|
/// The fixity of an OperatorDecl.
|
|
enum class OperatorFixity : uint8_t {
|
|
Infix,
|
|
Prefix,
|
|
Postfix
|
|
};
|
|
|
|
inline void simple_display(llvm::raw_ostream &out, OperatorFixity fixity) {
|
|
switch (fixity) {
|
|
case OperatorFixity::Infix:
|
|
out << "infix";
|
|
return;
|
|
case OperatorFixity::Prefix:
|
|
out << "prefix";
|
|
return;
|
|
case OperatorFixity::Postfix:
|
|
out << "postfix";
|
|
return;
|
|
}
|
|
llvm_unreachable("Unhandled case in switch");
|
|
}
|
|
|
|
/// Abstract base class of operator declarations.
|
|
class OperatorDecl : public Decl {
|
|
SourceLoc OperatorLoc, NameLoc;
|
|
|
|
Identifier name;
|
|
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
friend class Decl;
|
|
public:
|
|
OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc,
|
|
Identifier Name, SourceLoc NameLoc)
|
|
: Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name)
|
|
{}
|
|
|
|
/// Retrieve the operator's fixity, corresponding to the concrete subclass
|
|
/// of the OperatorDecl.
|
|
OperatorFixity getFixity() const {
|
|
switch (getKind()) {
|
|
#define DECL(Id, Name) case DeclKind::Id: llvm_unreachable("Not an operator!");
|
|
#define OPERATOR_DECL(Id, Name)
|
|
#include "swift/AST/DeclNodes.def"
|
|
case DeclKind::InfixOperator:
|
|
return OperatorFixity::Infix;
|
|
case DeclKind::PrefixOperator:
|
|
return OperatorFixity::Prefix;
|
|
case DeclKind::PostfixOperator:
|
|
return OperatorFixity::Postfix;
|
|
}
|
|
llvm_unreachable("invalid decl kind");
|
|
}
|
|
|
|
SourceLoc getOperatorLoc() const { return OperatorLoc; }
|
|
SourceLoc getNameLoc() const { return NameLoc; }
|
|
Identifier getName() const { return name; }
|
|
|
|
// This is needed to allow templated code to work with both ValueDecls and
|
|
// OperatorDecls.
|
|
DeclBaseName getBaseName() const { return name; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
// Workaround: http://llvm.org/PR35906
|
|
if (DeclKind::Last_Decl == DeclKind::Last_OperatorDecl)
|
|
return D->getKind() >= DeclKind::First_OperatorDecl;
|
|
return D->getKind() >= DeclKind::First_OperatorDecl
|
|
&& D->getKind() <= DeclKind::Last_OperatorDecl;
|
|
}
|
|
};
|
|
|
|
/// Declares the behavior of an infix operator. For example:
|
|
///
|
|
/// \code
|
|
/// infix operator /+/ : AdditionPrecedence, Numeric
|
|
/// \endcode
|
|
class InfixOperatorDecl : public OperatorDecl {
|
|
SourceLoc ColonLoc, PrecedenceGroupLoc;
|
|
Identifier PrecedenceGroupName;
|
|
|
|
public:
|
|
InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name,
|
|
SourceLoc nameLoc, SourceLoc colonLoc,
|
|
Identifier precedenceGroupName,
|
|
SourceLoc precedenceGroupLoc)
|
|
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
|
|
ColonLoc(colonLoc), PrecedenceGroupLoc(precedenceGroupLoc),
|
|
PrecedenceGroupName(precedenceGroupName) {}
|
|
|
|
SourceLoc getEndLoc() const {
|
|
if (getPrecedenceGroupLoc().isValid())
|
|
return getPrecedenceGroupLoc();
|
|
|
|
return getNameLoc();
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { getOperatorLoc(), getEndLoc() };
|
|
}
|
|
|
|
SourceLoc getColonLoc() const { return ColonLoc; }
|
|
|
|
Identifier getPrecedenceGroupName() const { return PrecedenceGroupName; }
|
|
SourceLoc getPrecedenceGroupLoc() const { return PrecedenceGroupLoc; }
|
|
PrecedenceGroupDecl *getPrecedenceGroup() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::InfixOperator;
|
|
}
|
|
};
|
|
|
|
/// Declares the behavior of a prefix operator. For example:
|
|
///
|
|
/// \code
|
|
/// prefix operator /+/ {}
|
|
/// \endcode
|
|
class PrefixOperatorDecl : public OperatorDecl {
|
|
public:
|
|
PrefixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
|
|
SourceLoc NameLoc)
|
|
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc)
|
|
{}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { getOperatorLoc(), getNameLoc() };
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PrefixOperator;
|
|
}
|
|
};
|
|
|
|
/// Declares the behavior of a postfix operator. For example:
|
|
///
|
|
/// \code
|
|
/// postfix operator /+/ {}
|
|
/// \endcode
|
|
class PostfixOperatorDecl : public OperatorDecl {
|
|
public:
|
|
PostfixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
|
|
SourceLoc NameLoc)
|
|
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc)
|
|
{}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { getOperatorLoc(), getNameLoc() };
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PostfixOperator;
|
|
}
|
|
};
|
|
|
|
class MacroExpansionDecl;
|
|
|
|
/// Represents a missing declaration in the source code.
|
|
///
|
|
/// This is used for parser recovery, e.g. when parsing a floating
|
|
/// attribute list, and to represent placeholders for unexpanded
|
|
/// declarations generated by macros.
|
|
class MissingDecl : public Decl {
|
|
/// If this missing decl represents an unexpanded peer generated by a macro,
|
|
/// \c unexpandedMacro contains the macro reference and the base declaration
|
|
/// where the macro expansion applies.
|
|
struct {
|
|
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *> macroRef;
|
|
Decl *baseDecl;
|
|
} unexpandedMacro;
|
|
|
|
/// The location that the decl would be if it wasn't missing.
|
|
SourceLoc Loc;
|
|
|
|
MissingDecl(DeclContext *DC, SourceLoc loc)
|
|
: Decl(DeclKind::Missing, DC), Loc(loc) {
|
|
setImplicit();
|
|
}
|
|
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const { return Loc; }
|
|
|
|
public:
|
|
static MissingDecl *create(ASTContext &ctx, DeclContext *DC, SourceLoc loc) {
|
|
return new (ctx) MissingDecl(DC, loc);
|
|
}
|
|
|
|
SourceRange getSourceRange() const { return SourceRange(Loc); }
|
|
|
|
static MissingDecl *
|
|
forUnexpandedMacro(
|
|
llvm::PointerUnion<FreestandingMacroExpansion *, CustomAttr *> macroRef,
|
|
Decl *baseDecl) {
|
|
auto &ctx = baseDecl->getASTContext();
|
|
auto *dc = baseDecl->getDeclContext();
|
|
auto *missing = new (ctx) MissingDecl(dc, SourceLoc());
|
|
|
|
missing->unexpandedMacro.macroRef = macroRef;
|
|
missing->unexpandedMacro.baseDecl = baseDecl;
|
|
|
|
return missing;
|
|
}
|
|
|
|
using MacroExpandedDeclCallback = llvm::function_ref<void(ValueDecl *)>;
|
|
void forEachMacroExpandedDecl(MacroExpandedDeclCallback callback);
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Missing;
|
|
}
|
|
};
|
|
|
|
/// Represents a hole where a declaration should have been.
|
|
///
|
|
/// Among other things, these are used to keep vtable layout consistent.
|
|
class MissingMemberDecl : public Decl {
|
|
DeclName Name;
|
|
|
|
MissingMemberDecl(DeclContext *DC, DeclName name,
|
|
unsigned vtableEntries,
|
|
unsigned fieldOffsetVectorEntries)
|
|
: Decl(DeclKind::MissingMember, DC), Name(name) {
|
|
Bits.MissingMemberDecl.NumberOfVTableEntries = vtableEntries;
|
|
assert(getNumberOfVTableEntries() == vtableEntries && "not enough bits");
|
|
Bits.MissingMemberDecl.NumberOfFieldOffsetVectorEntries =
|
|
fieldOffsetVectorEntries;
|
|
assert(getNumberOfFieldOffsetVectorEntries() == fieldOffsetVectorEntries
|
|
&& "not enough bits");
|
|
setImplicit();
|
|
}
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const {
|
|
return SourceLoc();
|
|
}
|
|
public:
|
|
static MissingMemberDecl *
|
|
create(ASTContext &ctx, DeclContext *DC, DeclName name,
|
|
unsigned numVTableEntries, bool hasStorage) {
|
|
assert(!numVTableEntries || isa<ProtocolDecl>(DC) || isa<ClassDecl>(DC) &&
|
|
"Only classes and protocols have vtable/witness table entries");
|
|
assert(!hasStorage || !isa<ProtocolDecl>(DC) &&
|
|
"Protocols cannot have missing stored properties");
|
|
|
|
return new (ctx) MissingMemberDecl(DC, name, numVTableEntries, hasStorage);
|
|
}
|
|
|
|
DeclName getName() const {
|
|
return Name;
|
|
}
|
|
|
|
unsigned getNumberOfVTableEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfVTableEntries;
|
|
}
|
|
|
|
unsigned getNumberOfFieldOffsetVectorEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfFieldOffsetVectorEntries;
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange();
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::MissingMember;
|
|
}
|
|
};
|
|
|
|
/// Provides a declaration of a macro.
|
|
///
|
|
/// Macros are declared within the source code with the `macro` introducer.
|
|
///
|
|
/// Macros are defined externally via conformances to the 'Macro' type
|
|
/// that is part of swift-syntax, and are introduced into the compiler via
|
|
/// various mechanisms (e.g., in-process macros provided as builtins or
|
|
/// loaded via shared library, and so on).
|
|
class MacroDecl : public GenericContext, public ValueDecl {
|
|
public:
|
|
/// The location of the 'macro' keyword.
|
|
SourceLoc macroLoc;
|
|
|
|
/// The parameter list.
|
|
ParameterList *parameterList;
|
|
|
|
/// Where the '->' is located, if present.
|
|
SourceLoc arrowLoc;
|
|
|
|
/// The result type.
|
|
TypeLoc resultType;
|
|
|
|
/// The macro definition, which should always be a
|
|
/// \c MacroExpansionExpr in well-formed code.
|
|
Expr *definition;
|
|
|
|
MacroDecl(SourceLoc macroLoc, DeclName name, SourceLoc nameLoc,
|
|
GenericParamList *genericParams,
|
|
ParameterList *parameterList,
|
|
SourceLoc arrowLoc,
|
|
TypeRepr *resultType,
|
|
Expr *definition,
|
|
DeclContext *parent);
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Retrieve the interface type produced when expanding this macro.
|
|
Type getResultInterfaceType() const;
|
|
|
|
/// Returns the result interface type of this macro if it has already been
|
|
/// computed, otherwise `nullopt`. This should only be used for dumping.
|
|
std::optional<Type> getCachedResultInterfaceType() const;
|
|
|
|
/// Determine the contexts in which this macro can be applied.
|
|
MacroRoles getMacroRoles() const;
|
|
|
|
/// Retrieve the attribute that declared the given macro role.
|
|
const MacroRoleAttr *getMacroRoleAttr(MacroRole role) const;
|
|
|
|
/// Populate the \c names vector with the decl names introduced
|
|
/// by a given role of this macro.
|
|
void getIntroducedNames(MacroRole role, ValueDecl *attachedTo,
|
|
SmallVectorImpl<DeclName> &names) const;
|
|
|
|
/// Populate the \c conformances vector with the protocols that
|
|
/// this macro generates conformances to.
|
|
///
|
|
/// Only extension macros can add conformances; no results will
|
|
/// be added if this macro does not contain an extension role.
|
|
void getIntroducedConformances(
|
|
NominalTypeDecl *attachedTo,
|
|
MacroRole role,
|
|
SmallVectorImpl<ProtocolDecl *> &conformances) const;
|
|
|
|
/// Returns a DeclName that represents arbitrary names.
|
|
static DeclName getArbitraryName() {
|
|
return DeclName();
|
|
}
|
|
|
|
/// Returns a DeclName that acts as a stand-in for all unique names that
|
|
/// are manufactured by the macro expansion context's `makeUniqueName`.
|
|
static DeclName getUniqueNamePlaceholder(ASTContext &ctx);
|
|
|
|
/// Determine whether the given name is the unique-name placeholder
|
|
/// produced by `getUniqueNamePlaceholder`.
|
|
static bool isUniqueNamePlaceholder(DeclName name);
|
|
|
|
/// Determine whether the given name is one of the unique names manufactured
|
|
/// by the macro expansion context's `makeUniqueName`.
|
|
static bool isUniqueMacroName(StringRef name);
|
|
|
|
/// Determine whether the given name is one of the unique names manufactured
|
|
/// by the macro expansion context's `makeUniqueName`.
|
|
static bool isUniqueMacroName(DeclBaseName name);
|
|
|
|
/// Retrieve the definition of this macro.
|
|
MacroDefinition getDefinition() const;
|
|
|
|
/// Set the definition of this macro
|
|
void setDefinition(MacroDefinition definition);
|
|
|
|
/// Retrieve the parameter list of this macro.
|
|
ParameterList *getParameterList() const { return parameterList; }
|
|
|
|
/// Retrieve the builtin macro kind for this macro, or \c None if it is a
|
|
/// user-defined macro with no special semantics.
|
|
std::optional<BuiltinMacroKind> getBuiltinKind() const;
|
|
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Macro;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using DeclContext::operator delete;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
class MacroExpansionDecl : public Decl, public FreestandingMacroExpansion {
|
|
|
|
public:
|
|
MacroExpansionDecl(DeclContext *dc, MacroExpansionInfo *info);
|
|
|
|
static MacroExpansionDecl *create(DeclContext *dc, SourceLoc poundLoc,
|
|
DeclNameRef macro, DeclNameLoc macroLoc,
|
|
SourceLoc leftAngleLoc,
|
|
ArrayRef<TypeRepr *> genericArgs,
|
|
SourceLoc rightAngleLoc,
|
|
ArgumentList *args);
|
|
|
|
DeclContext *getDeclContext() const { return Decl::getDeclContext(); }
|
|
|
|
SourceRange getSourceRange() const {
|
|
return getExpansionInfo()->getSourceRange();
|
|
}
|
|
SourceLoc getLocFromSource() const { return getExpansionInfo()->SigilLoc; }
|
|
|
|
/// Enumerate the nodes produced by expanding this macro expansion.
|
|
void forEachExpandedNode(llvm::function_ref<void(ASTNode)> callback) const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::MacroExpansion;
|
|
}
|
|
static bool classof(const FreestandingMacroExpansion *expansion) {
|
|
return expansion->getFreestandingMacroKind() == FreestandingMacroKind::Decl;
|
|
}
|
|
};
|
|
|
|
/// UsingDecl - This represents a single `using` declaration, e.g.:
|
|
/// using @MainActor
|
|
class UsingDecl : public Decl {
|
|
friend class Decl;
|
|
|
|
private:
|
|
SourceLoc UsingLoc, SpecifierLoc;
|
|
|
|
UsingDecl(SourceLoc usingLoc, SourceLoc specifierLoc,
|
|
UsingSpecifier specifier, DeclContext *parent);
|
|
|
|
public:
|
|
UsingSpecifier getSpecifier() const {
|
|
return static_cast<UsingSpecifier>(Bits.UsingDecl.Specifier);
|
|
}
|
|
|
|
std::string getSpecifierName() const;
|
|
|
|
SourceLoc getLocFromSource() const { return UsingLoc; }
|
|
SourceRange getSourceRange() const { return {UsingLoc, SpecifierLoc}; }
|
|
|
|
static UsingDecl *create(ASTContext &ctx, SourceLoc usingLoc,
|
|
SourceLoc specifierLoc, UsingSpecifier specifier,
|
|
DeclContext *parent);
|
|
|
|
static bool classof(const Decl *D) { return D->getKind() == DeclKind::Using; }
|
|
};
|
|
|
|
inline void
|
|
AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) {
|
|
Accessors.setInt(accessLevel);
|
|
if (auto setter = getAccessor(AccessorKind::Set))
|
|
setter->overwriteAccess(accessLevel);
|
|
if (auto modify = getAccessor(AccessorKind::Modify))
|
|
modify->overwriteAccess(accessLevel);
|
|
if (auto mutableAddressor = getAccessor(AccessorKind::MutableAddress))
|
|
mutableAddressor->overwriteAccess(accessLevel);
|
|
}
|
|
|
|
/// Constructors and destructors always have a 'self' parameter,
|
|
/// which is stored in an instance member. Functions only have a
|
|
/// 'self' if they are declared inside of a nominal type or extension,
|
|
/// in which case we tail-allocate storage for it.
|
|
inline ParamDecl **AbstractFunctionDecl::getImplicitSelfDeclStorage() {
|
|
switch (getKind()) {
|
|
default: llvm_unreachable("Unknown AbstractFunctionDecl!");
|
|
case DeclKind::Constructor:
|
|
return cast<ConstructorDecl>(this)->getImplicitSelfDeclStorage();
|
|
case DeclKind::Destructor:
|
|
return cast<DestructorDecl>(this)->getImplicitSelfDeclStorage();
|
|
case DeclKind::Func:
|
|
case DeclKind::Accessor:
|
|
return cast<FuncDecl>(this)->getImplicitSelfDeclStorage();
|
|
}
|
|
}
|
|
|
|
inline ParamDecl **FuncDecl::getImplicitSelfDeclStorage() {
|
|
if (!hasImplicitSelfDecl())
|
|
return nullptr;
|
|
|
|
if (!isa<AccessorDecl>(this)) {
|
|
assert(getKind() == DeclKind::Func && "no new kinds of functions");
|
|
return reinterpret_cast<ParamDecl **>(this+1);
|
|
}
|
|
return reinterpret_cast<ParamDecl **>(static_cast<AccessorDecl*>(this)+1);
|
|
}
|
|
|
|
inline DeclIterator &DeclIterator::operator++() {
|
|
Current = Current->NextDecl;
|
|
return *this;
|
|
}
|
|
|
|
inline bool AbstractFunctionDecl::hasForcedStaticDispatch() const {
|
|
if (auto func = dyn_cast<FuncDecl>(this))
|
|
return func->hasForcedStaticDispatch();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::isStatic() const {
|
|
// Currently, only storage and function decls can be static/class.
|
|
if (auto storage = dyn_cast<AbstractStorageDecl>(this))
|
|
return storage->isStatic();
|
|
if (auto func = dyn_cast<FuncDecl>(this))
|
|
return func->isStatic();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::isImportAsMember() const {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
|
|
return func->isImportAsMember();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::hasCurriedSelf() const {
|
|
if (auto *afd = dyn_cast<AbstractFunctionDecl>(this))
|
|
return afd->hasImplicitSelfDecl();
|
|
if (isa<EnumElementDecl>(this))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
inline unsigned ValueDecl::getNumCurryLevels() const {
|
|
unsigned curryLevels = 0;
|
|
if (hasParameterList())
|
|
curryLevels++;
|
|
if (hasCurriedSelf())
|
|
curryLevels++;
|
|
return curryLevels;
|
|
}
|
|
|
|
inline bool Decl::isSyntacticallyOverridable() const {
|
|
if (isa<VarDecl>(this) ||
|
|
isa<SubscriptDecl>(this) ||
|
|
isa<FuncDecl>(this) ||
|
|
isa<DestructorDecl>(this)) {
|
|
if (static_cast<const ValueDecl*>(this)->isFinal()) {
|
|
return false;
|
|
}
|
|
auto classDecl = getDeclContext()->getSelfClassDecl();
|
|
return classDecl && !classDecl->isActor() && !classDecl->isFinal();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline GenericParamKey::GenericParamKey(const GenericTypeParamDecl *d)
|
|
: ParameterPack(d->isParameterPack()), Depth(d->getDepth()),
|
|
Index(d->getIndex()) {}
|
|
|
|
inline const GenericContext *Decl::getAsGenericContext() const {
|
|
switch (getKind()) {
|
|
default: return nullptr;
|
|
#define DECL(Id, Parent) // See previous line
|
|
#define GENERIC_DECL(Id, Parent) \
|
|
case DeclKind::Id: \
|
|
return static_cast<const Id##Decl*>(this);
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
}
|
|
|
|
inline bool DeclContext::classof(const Decl *D) {
|
|
switch (D->getKind()) { //
|
|
default: return false;
|
|
#define DECL(ID, PARENT) // See previous line
|
|
#define CONTEXT_DECL(ID, PARENT) \
|
|
case DeclKind::ID: return true;
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
}
|
|
|
|
inline bool GenericContext::classof(const Decl *D) {
|
|
switch (D->getKind()) { //
|
|
default: return false;
|
|
#define DECL(ID, PARENT) // See previous line
|
|
#define GENERIC_DECL(ID, PARENT) \
|
|
case DeclKind::ID: return true;
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
}
|
|
|
|
inline DeclContext *DeclContext::castDeclToDeclContext(const Decl *D) {
|
|
// XXX -- ModuleDecl is not defined in Decl.h, but because DeclContexts
|
|
// preface decls in memory, any DeclContext type will due.
|
|
const DeclContext *DC = static_cast<const ExtensionDecl*>(D);
|
|
switch (D->getKind()) {
|
|
default: llvm_unreachable("Not a DeclContext");
|
|
#define DECL(ID, PARENT) // See previous line
|
|
#define CONTEXT_DECL(ID, PARENT) \
|
|
case DeclKind::ID:
|
|
#include "swift/AST/DeclNodes.def"
|
|
return const_cast<DeclContext *>(DC);
|
|
}
|
|
}
|
|
|
|
inline EnumElementDecl *EnumDecl::getUniqueElement(bool hasValue) const {
|
|
EnumElementDecl *result = nullptr;
|
|
bool found = false;
|
|
for (auto elt : getAllElements()) {
|
|
if (elt->hasAssociatedValues() == hasValue) {
|
|
if (found)
|
|
return nullptr;
|
|
found = true;
|
|
result = elt;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// Retrieve the parameter list for a given declaration context, or nullptr if
|
|
/// there is none.
|
|
ParameterList *getParameterList(DeclContext *source);
|
|
|
|
/// Retrieve parameter declaration from the given source at given index, or
|
|
/// nullptr if the source does not have a parameter list.
|
|
const ParamDecl *getParameterAt(ConcreteDeclRef declRef, unsigned index);
|
|
|
|
/// Retrieve parameter declaration from the given source at given index, or
|
|
/// nullptr if the source does not have a parameter list.
|
|
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
|
|
|
|
/// Retrieve parameter declaration from the given source at given index, or
|
|
/// nullptr if the source does not have a parameter list.
|
|
const ParamDecl *getParameterAt(const DeclContext *source, unsigned index);
|
|
|
|
class ABIRole {
|
|
public:
|
|
enum Value : uint8_t {
|
|
Neither = 0,
|
|
ProvidesABI = 1 << 0,
|
|
ProvidesAPI = 1 << 1,
|
|
Either = ProvidesABI | ProvidesAPI,
|
|
};
|
|
|
|
Value value;
|
|
|
|
ABIRole(Value value)
|
|
: value(value)
|
|
{ }
|
|
|
|
ABIRole()
|
|
: ABIRole(Neither)
|
|
{ }
|
|
|
|
explicit ABIRole(NLOptions opts);
|
|
|
|
template<typename FlagType>
|
|
explicit ABIRole(OptionSet<FlagType> flags)
|
|
: value(flags.contains(FlagType::ABIProviding) ? ProvidesABI : ProvidesAPI)
|
|
{ }
|
|
|
|
inline ABIRole operator|(ABIRole rhs) const {
|
|
return ABIRole(ABIRole::Value(value | rhs.value));
|
|
}
|
|
inline ABIRole &operator|=(ABIRole rhs) {
|
|
value = ABIRole::Value(value | rhs.value);
|
|
return *this;
|
|
}
|
|
inline ABIRole operator&(ABIRole rhs) const {
|
|
return ABIRole(ABIRole::Value(value & rhs.value));
|
|
}
|
|
inline ABIRole &operator&=(ABIRole rhs) {
|
|
value = ABIRole::Value(value & rhs.value);
|
|
return *this;
|
|
}
|
|
inline ABIRole operator~() const {
|
|
return ABIRole(ABIRole::Value(~value));
|
|
}
|
|
|
|
operator bool() const {
|
|
return value != Neither;
|
|
}
|
|
};
|
|
|
|
namespace abi_role_detail {
|
|
|
|
using Storage = llvm::PointerIntPair<Decl *, 2, ABIRole::Value>;
|
|
Storage computeStorage(Decl *decl);
|
|
|
|
}
|
|
|
|
/// Specifies the \c ABIAttr -related behavior of this declaration
|
|
/// and provides access to its counterpart.
|
|
///
|
|
/// A given declaration may provide the API, the ABI, or both. If it provides
|
|
/// API, the counterpart is the matching ABI-providing decl; if it provides
|
|
/// ABI, the countepart is the matching API-providing decl. A declaration
|
|
/// which provides both API and ABI is its own counterpart.
|
|
///
|
|
/// If the counterpart is \c nullptr , this indicates a fundamental mismatch
|
|
/// between decl and counterpart. Sometimes this mismatch is a difference in
|
|
/// decl kind; in these cases, \c getCounterpartUnchecked() will return the
|
|
/// incorrect counterpart.
|
|
template<typename SpecificDecl>
|
|
class ABIRoleInfo {
|
|
friend abi_role_detail::Storage abi_role_detail::computeStorage(Decl *);
|
|
|
|
abi_role_detail::Storage counterpartAndFlags;
|
|
|
|
ABIRoleInfo(abi_role_detail::Storage storage)
|
|
: counterpartAndFlags(storage)
|
|
{ }
|
|
|
|
public:
|
|
explicit ABIRoleInfo(const SpecificDecl *decl)
|
|
: ABIRoleInfo(abi_role_detail::computeStorage(const_cast<SpecificDecl *>(decl)))
|
|
{ }
|
|
|
|
Decl *getCounterpartUnchecked() const {
|
|
return counterpartAndFlags.getPointer();
|
|
}
|
|
|
|
SpecificDecl *getCounterpart() const {
|
|
return dyn_cast_or_null<SpecificDecl>(getCounterpartUnchecked());
|
|
}
|
|
|
|
ABIRole getRole() const {
|
|
return ABIRole(ABIRole::Value(counterpartAndFlags.getInt()));
|
|
}
|
|
|
|
bool matches(ABIRole desiredRole) const {
|
|
return getRole() & desiredRole;
|
|
}
|
|
|
|
template<typename Options>
|
|
bool matchesOptions(Options opts) const {
|
|
return matches(ABIRole(opts));
|
|
}
|
|
|
|
bool providesABI() const {
|
|
return matches(ABIRole::ProvidesABI);
|
|
}
|
|
|
|
bool providesAPI() const {
|
|
return matches(ABIRole::ProvidesAPI);
|
|
}
|
|
|
|
bool hasABIAttr() const {
|
|
return !providesABI();
|
|
}
|
|
};
|
|
|
|
template<typename SpecificDecl>
|
|
ABIRoleInfo(const SpecificDecl *decl) -> ABIRoleInfo<SpecificDecl>;
|
|
|
|
StringRef
|
|
getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article,
|
|
std::optional<bool> underscored = std::nullopt);
|
|
StringRef getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article,
|
|
bool underscored);
|
|
|
|
void simple_display(llvm::raw_ostream &out,
|
|
OptionSet<NominalTypeDecl::LookupDirectFlags> options);
|
|
|
|
/// Display Decl subclasses.
|
|
void simple_display(llvm::raw_ostream &out, const Decl *decl);
|
|
|
|
/// Display ValueDecl subclasses.
|
|
void simple_display(llvm::raw_ostream &out, const ValueDecl *decl);
|
|
|
|
/// Display ExtensionDecls.
|
|
inline void simple_display(llvm::raw_ostream &out, const ExtensionDecl *decl) {
|
|
simple_display(out, static_cast<const Decl *>(decl));
|
|
}
|
|
|
|
/// Display NominalTypeDecls.
|
|
inline void simple_display(llvm::raw_ostream &out,
|
|
const NominalTypeDecl *decl) {
|
|
simple_display(out, static_cast<const Decl *>(decl));
|
|
}
|
|
|
|
inline void simple_display(llvm::raw_ostream &out,
|
|
const AssociatedTypeDecl *decl) {
|
|
simple_display(out, static_cast<const Decl *>(decl));
|
|
}
|
|
|
|
/// Display GenericContext.
|
|
///
|
|
/// The template keeps this sorted down in the overload set relative to the
|
|
/// more concrete overloads with Decl pointers thereby breaking a potential ambiguity.
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_same<T, GenericContext>::value>::type
|
|
simple_display(llvm::raw_ostream &out, const T *GC) {
|
|
simple_display(out, GC->getAsDecl());
|
|
}
|
|
|
|
/// Display GenericParamList.
|
|
void simple_display(llvm::raw_ostream &out, const GenericParamList *GPL);
|
|
|
|
/// Extract the source location from the given declaration.
|
|
SourceLoc extractNearestSourceLoc(const Decl *decl);
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const ExtensionDecl *ext) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(ext));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const GenericTypeDecl *type) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(type));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const NominalTypeDecl *type) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(type));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const AbstractFunctionDecl *func) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(func));
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|