mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
6681 lines
226 KiB
C++
6681 lines
226 KiB
C++
//===--- Decl.h - Swift Language Declaration ASTs ---------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 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/CaptureInfo.h"
|
|
#include "swift/AST/ClangNode.h"
|
|
#include "swift/AST/ConcreteDeclRef.h"
|
|
#include "swift/AST/DefaultArgumentKind.h"
|
|
#include "swift/AST/DiagnosticConsumer.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/GenericParamKey.h"
|
|
#include "swift/AST/IfConfigClause.h"
|
|
#include "swift/AST/LayoutConstraint.h"
|
|
#include "swift/AST/StorageImpl.h"
|
|
#include "swift/AST/TypeAlignments.h"
|
|
#include "swift/AST/TypeWalker.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/Witness.h"
|
|
#include "swift/Basic/ArrayRefView.h"
|
|
#include "swift/Basic/Compiler.h"
|
|
#include "swift/Basic/InlineBitfield.h"
|
|
#include "swift/Basic/OptionalEnum.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/Support/TrailingObjects.h"
|
|
#include <type_traits>
|
|
|
|
namespace swift {
|
|
enum class AccessSemantics : unsigned char;
|
|
class AccessorDecl;
|
|
class ApplyExpr;
|
|
class GenericEnvironment;
|
|
class ArchetypeType;
|
|
class ASTContext;
|
|
struct ASTNode;
|
|
class ASTPrinter;
|
|
class ASTWalker;
|
|
class ConstructorDecl;
|
|
class DestructorDecl;
|
|
class DiagnosticEngine;
|
|
class DynamicSelfType;
|
|
class Type;
|
|
class Expr;
|
|
class DeclRefExpr;
|
|
class ForeignErrorConvention;
|
|
class LiteralExpr;
|
|
class BraceStmt;
|
|
class DeclAttributes;
|
|
class GenericContext;
|
|
class GenericSignature;
|
|
class GenericTypeParamDecl;
|
|
class GenericTypeParamType;
|
|
class LazyResolver;
|
|
class ModuleDecl;
|
|
class EnumCaseDecl;
|
|
class EnumElementDecl;
|
|
class ParameterList;
|
|
class ParameterTypeFlags;
|
|
class Pattern;
|
|
struct PrintOptions;
|
|
class ProtocolDecl;
|
|
class ProtocolType;
|
|
struct RawComment;
|
|
enum class ResilienceExpansion : unsigned;
|
|
class TypeAliasDecl;
|
|
class Stmt;
|
|
class SubscriptDecl;
|
|
class UnboundGenericType;
|
|
class ValueDecl;
|
|
class VarDecl;
|
|
|
|
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,
|
|
IfConfig,
|
|
PoundDiagnostic,
|
|
PatternBinding,
|
|
Var,
|
|
Param,
|
|
Let,
|
|
StaticVar,
|
|
StaticLet,
|
|
ClassVar,
|
|
ClassLet,
|
|
InfixOperator,
|
|
PrefixOperator,
|
|
PostfixOperator,
|
|
PrecedenceGroup,
|
|
TypeAlias,
|
|
GenericTypeParam,
|
|
AssociatedType,
|
|
Type,
|
|
Enum,
|
|
Struct,
|
|
Class,
|
|
Protocol,
|
|
GenericEnum,
|
|
GenericStruct,
|
|
GenericClass,
|
|
GenericType,
|
|
Subscript,
|
|
Constructor,
|
|
Destructor,
|
|
LocalFunction,
|
|
GlobalFunction,
|
|
OperatorFunction,
|
|
Method,
|
|
StaticMethod,
|
|
ClassMethod,
|
|
Getter,
|
|
Setter,
|
|
MaterializeForSet,
|
|
Addressor,
|
|
MutableAddressor,
|
|
ReadAccessor,
|
|
ModifyAccessor,
|
|
WillSet,
|
|
DidSet,
|
|
EnumElement,
|
|
Module,
|
|
MissingMember,
|
|
Requirement,
|
|
};
|
|
|
|
/// Keeps track of stage of circularity checking for the given protocol.
|
|
enum class CircularityCheck {
|
|
/// Circularity has not yet been checked.
|
|
Unchecked,
|
|
/// We're currently checking circularity.
|
|
Checking,
|
|
/// Circularity has already been checked.
|
|
Checked
|
|
};
|
|
|
|
/// 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,
|
|
};
|
|
|
|
/// Diagnostic printing of \c StaticSpellingKind.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK);
|
|
|
|
/// 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 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;
|
|
|
|
OverloadSignature()
|
|
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
|
|
IsVariable(false), IsFunction(false), InProtocolExtension(false),
|
|
InExtensionOfGenericType(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);
|
|
|
|
/// Decl - Base class for all declarations in Swift.
|
|
class alignas(1 << DeclAlignInBits) Decl {
|
|
public:
|
|
enum class ValidationState {
|
|
Unchecked,
|
|
Checking,
|
|
CheckingWithValidSignature,
|
|
Checked,
|
|
};
|
|
|
|
protected:
|
|
union { uint64_t OpaqueBits;
|
|
|
|
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+1+1+1,
|
|
Kind : bitmax(NumDeclKindBits,8),
|
|
|
|
/// \brief Whether this declaration is invalid.
|
|
Invalid : 1,
|
|
|
|
/// \brief Whether this declaration was implicitly created, e.g.,
|
|
/// an implicit constructor in a struct.
|
|
Implicit : 1,
|
|
|
|
/// \brief Whether this declaration was mapped directly from a Clang AST.
|
|
///
|
|
/// Use getClangNode() to retrieve the corresponding Clang AST.
|
|
FromClang : 1,
|
|
|
|
/// \brief Whether we've already performed early attribute validation.
|
|
/// FIXME: This is ugly.
|
|
EarlyAttrValidation : 1,
|
|
|
|
/// \brief The validation state of this declaration.
|
|
ValidationState : 2,
|
|
|
|
/// \brief Whether this declaration was added to the surrounding
|
|
/// DeclContext of an active #if config clause.
|
|
EscapedFromIfConfig : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(PatternBindingDecl, Decl, 1+2+16,
|
|
/// \brief Whether this pattern binding declares static variables.
|
|
IsStatic : 1,
|
|
|
|
/// \brief Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
: NumPadBits,
|
|
|
|
/// \brief 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,
|
|
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
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AbstractStorageDecl, ValueDecl, 1+1+1+1,
|
|
/// Whether the getter is mutating.
|
|
IsGetterMutating : 1,
|
|
|
|
/// Whether the setter is mutating.
|
|
IsSetterMutating : 1,
|
|
|
|
/// Whether this represents physical storage.
|
|
HasStorage : 1,
|
|
|
|
/// Whether this storage supports semantic mutation in some way.
|
|
SupportsMutation : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+4+1+1+1+1,
|
|
/// \brief Whether this property is a type property (currently unfortunately
|
|
/// called 'static').
|
|
IsStatic : 1,
|
|
|
|
/// \brief The specifier associated with this variable or parameter. This
|
|
/// determines the storage semantics of the value e.g. mutability.
|
|
Specifier : 4,
|
|
|
|
/// \brief Whether this declaration was an element of a capture list.
|
|
IsCaptureList : 1,
|
|
|
|
/// \brief Whether this vardecl has an initial value bound to it in a way
|
|
/// that isn't represented in the AST with an initializer in the pattern
|
|
/// binding. This happens in cases like "for i in ...", switch cases, etc.
|
|
HasNonPatternBindingInit : 1,
|
|
|
|
/// \brief 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,
|
|
|
|
/// \brief Whether this is a property defined in the debugger's REPL.
|
|
/// FIXME: Remove this once LLDB has proper support for resilience.
|
|
IsREPLVar : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1 + NumDefaultArgumentKindBits,
|
|
/// True if the type is implicitly specified in the source, but this has an
|
|
/// apparently valid typeRepr. This is used in accessors, which look like:
|
|
/// set (value) {
|
|
/// but need to get the typeRepr from the property as a whole so Sema can
|
|
/// resolve the type.
|
|
IsTypeLocImplicit : 1,
|
|
|
|
/// Information about a symbolic default argument, like #file.
|
|
defaultArgumentKind : NumDefaultArgumentKindBits
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(EnumElementDecl, ValueDecl, 1,
|
|
/// \brief The ResilienceExpansion to use for default arguments.
|
|
DefaultArgumentResilienceExpansion : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1,
|
|
/// \see AbstractFunctionDecl::BodyKind
|
|
BodyKind : 3,
|
|
|
|
/// 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 body throws.
|
|
Throws : 1,
|
|
|
|
/// Whether this function requires a new vtable entry.
|
|
NeedsNewVTableEntry : 1,
|
|
|
|
/// Whether NeedsNewVTableEntry is valid.
|
|
HasComputedNeedsNewVTableEntry : 1,
|
|
|
|
/// The ResilienceExpansion to use for default arguments.
|
|
DefaultArgumentResilienceExpansion : 1,
|
|
|
|
/// Whether this member was synthesized as part of a derived
|
|
/// protocol conformance.
|
|
Synthesized : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+2+1+1+2,
|
|
/// Whether this function is a 'static' method.
|
|
IsStatic : 1,
|
|
|
|
/// \brief Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
/// Whether we are statically dispatched even if overridable
|
|
ForcedStaticDispatch : 1,
|
|
|
|
/// Whether this function has a dynamic Self return type.
|
|
HasDynamicSelf : 1,
|
|
|
|
/// Backing bits for 'self' access kind.
|
|
SelfAccess : 2
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4+3,
|
|
/// The kind of accessor this is.
|
|
AccessorKind : 4,
|
|
|
|
/// The kind of addressor this is.
|
|
AddressorKind : 3
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 3+2+2+1,
|
|
/// The body initialization kind (+1), or zero if not yet computed.
|
|
///
|
|
/// This value is cached but is not serialized, because it is a property
|
|
/// of the definition of the constructor that is useful only to semantic
|
|
/// analysis and SIL generation.
|
|
ComputedBodyInitKind : 3,
|
|
|
|
/// The kind of initializer we have.
|
|
InitKind : 2,
|
|
|
|
/// The failability of this initializer, which is an OptionalTypeKind.
|
|
Failability : 2,
|
|
|
|
/// 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(AbstractTypeParamDecl, ValueDecl);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16,
|
|
: NumPadBits,
|
|
|
|
Depth : 16,
|
|
Index : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_EMPTY(GenericTypeDecl, ValueDecl);
|
|
|
|
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 we have already validated all members of the type that
|
|
/// affect layout.
|
|
HasValidatedLayout : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+1+2+8+16,
|
|
/// 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 ExistentialTypeSupported bit is valid.
|
|
ExistentialTypeSupportedValid : 1,
|
|
|
|
/// Whether the existential of this protocol can be represented.
|
|
ExistentialTypeSupported : 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 are currently computing inherited protocols.
|
|
ComputingInheritedProtocols : 1,
|
|
|
|
/// The stage of the circularity check for this protocol.
|
|
Circularity : 2,
|
|
|
|
: 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.
|
|
|
|
/// The number of requirements in the requirement signature.
|
|
NumRequirementsInSignature : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1,
|
|
/// Whether this class requires all of its instance variables to
|
|
/// have in-class initializers.
|
|
RequiresStoredPropertyInits : 1,
|
|
|
|
/// The stage of the inheritance circularity check for this class.
|
|
Circularity : 2,
|
|
|
|
/// Whether this class inherits its superclass's convenience initializers.
|
|
InheritsSuperclassInits : 1,
|
|
|
|
/// \see ClassDecl::ForeignKind
|
|
RawForeignKind : 2,
|
|
|
|
/// Whether this class contains a destructor decl.
|
|
///
|
|
/// A fully type-checked class always contains a destructor member, even if
|
|
/// it is implicit. This bit is used during parsing and type-checking to
|
|
/// control inserting the implicit destructor.
|
|
HasDestructorDecl : 1,
|
|
|
|
/// Whether the class has @objc ancestry.
|
|
ObjCKind : 3,
|
|
|
|
HasMissingDesignatedInitializers : 1,
|
|
HasMissingVTableEntries : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(StructDecl, NominalTypeDecl, 1,
|
|
/// True if this struct has storage for fields that aren't accessible in
|
|
/// Swift.
|
|
HasUnreferenceableStorage : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(EnumDecl, NominalTypeDecl, 2+2+1,
|
|
/// The stage of the raw type circularity check for this class.
|
|
Circularity : 2,
|
|
|
|
/// 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
|
|
);
|
|
|
|
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(ExtensionDecl, Decl, 3+1,
|
|
/// An encoding of the default and maximum access level for this extension.
|
|
///
|
|
/// 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 : 3,
|
|
|
|
/// Whether there is are lazily-loaded conformances for this extension.
|
|
HasLazyConformances : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(IfConfigDecl, Decl, 1,
|
|
/// Whether this decl is missing its closing '#endif'.
|
|
HadMissingEnd : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(PoundDiagnosticDecl, Decl, 1+1,
|
|
/// `true` if the diagnostic is an error, `false` if it's a warning.
|
|
IsError : 1,
|
|
|
|
/// Whether this diagnostic has already been emitted.
|
|
HasBeenEmitted : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(MissingMemberDecl, Decl, 1+2,
|
|
NumberOfFieldOffsetVectorEntries : 1,
|
|
NumberOfVTableEntries : 2
|
|
);
|
|
|
|
} Bits;
|
|
|
|
// 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;
|
|
|
|
private:
|
|
llvm::PointerUnion<DeclContext *, ASTContext *> Context;
|
|
|
|
Decl(const Decl&) = delete;
|
|
void operator=(const Decl&) = delete;
|
|
|
|
protected:
|
|
|
|
Decl(DeclKind kind, llvm::PointerUnion<DeclContext *, ASTContext *> context)
|
|
: Context(context) {
|
|
Bits.OpaqueBits = 0;
|
|
Bits.Decl.Kind = unsigned(kind);
|
|
Bits.Decl.Invalid = false;
|
|
Bits.Decl.Implicit = false;
|
|
Bits.Decl.FromClang = false;
|
|
Bits.Decl.EarlyAttrValidation = false;
|
|
Bits.Decl.ValidationState = unsigned(ValidationState::Unchecked);
|
|
Bits.Decl.EscapedFromIfConfig = false;
|
|
}
|
|
|
|
/// \brief Get the Clang node associated with this declaration.
|
|
ClangNode getClangNodeImpl() const;
|
|
|
|
/// \brief 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); }
|
|
|
|
/// \brief 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;
|
|
|
|
/// \brief Retrieve the module in which this declaration resides.
|
|
LLVM_READONLY
|
|
ModuleDecl *getModuleContext() 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 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() 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;
|
|
|
|
SourceLoc TrailingSemiLoc;
|
|
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump() const LLVM_ATTRIBUTE_USED,
|
|
"only for use within the debugger");
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump(const char *filename) const LLVM_ATTRIBUTE_USED,
|
|
"only for use within the debugger");
|
|
void dump(raw_ostream &OS, unsigned Indent = 0) const;
|
|
|
|
/// \brief 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;
|
|
|
|
/// \brief 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;
|
|
|
|
/// \brief 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);
|
|
|
|
/// \brief Return whether this declaration has been determined invalid.
|
|
bool isInvalid() const { return Bits.Decl.Invalid; }
|
|
|
|
/// \brief Mark this declaration invalid.
|
|
void setInvalid(bool isInvalid = true) { Bits.Decl.Invalid = isInvalid; }
|
|
|
|
/// \brief Determine whether this declaration was implicitly generated by the
|
|
/// compiler (rather than explicitly written in source code).
|
|
bool isImplicit() const { return Bits.Decl.Implicit; }
|
|
|
|
/// \brief Mark this declaration as implicit.
|
|
void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; }
|
|
|
|
/// Whether we have already done early attribute validation.
|
|
bool didEarlyAttrValidation() const { return Bits.Decl.EarlyAttrValidation; }
|
|
|
|
/// Set whether we've performed early attribute validation.
|
|
void setEarlyAttrValidation(bool validated = true) {
|
|
Bits.Decl.EarlyAttrValidation = validated;
|
|
}
|
|
|
|
/// Get the validation state.
|
|
ValidationState getValidationState() const {
|
|
return ValidationState(Bits.Decl.ValidationState);
|
|
}
|
|
|
|
private:
|
|
friend class DeclValidationRAII;
|
|
|
|
/// Set the validation state.
|
|
void setValidationState(ValidationState VS) {
|
|
assert(VS > getValidationState() && "Validation is unidirectional");
|
|
Bits.Decl.ValidationState = unsigned(VS);
|
|
}
|
|
|
|
public:
|
|
/// Whether the declaration is in the middle of validation or not.
|
|
bool isBeingValidated() const {
|
|
switch (getValidationState()) {
|
|
case ValidationState::Unchecked:
|
|
case ValidationState::Checked:
|
|
return false;
|
|
case ValidationState::Checking:
|
|
case ValidationState::CheckingWithValidSignature:
|
|
return true;
|
|
}
|
|
llvm_unreachable("Unknown ValidationState");
|
|
}
|
|
|
|
/// Update the validation state for the declaration to allow access to the
|
|
/// generic signature.
|
|
void setSignatureIsValidated() {
|
|
assert(getValidationState() == ValidationState::Checking);
|
|
setValidationState(ValidationState::CheckingWithValidSignature);
|
|
}
|
|
|
|
bool hasValidationStarted() const {
|
|
return getValidationState() > ValidationState::Unchecked;
|
|
}
|
|
|
|
/// Manually indicate that validation is complete for the declaration. For
|
|
/// example: during importing, code synthesis, or derived conformances.
|
|
///
|
|
/// For normal code validation, please use DeclValidationRAII instead.
|
|
///
|
|
/// FIXME -- Everything should use DeclValidationRAII instead of this.
|
|
void setValidationToChecked() {
|
|
if (!isBeingValidated())
|
|
Bits.Decl.ValidationState = unsigned(ValidationState::Checked);
|
|
}
|
|
|
|
bool escapedFromIfConfig() const {
|
|
return Bits.Decl.EscapedFromIfConfig;
|
|
}
|
|
|
|
void setEscapedFromIfConfig(bool Escaped) {
|
|
Bits.Decl.EscapedFromIfConfig = Escaped;
|
|
}
|
|
|
|
/// \returns the unparsed comment attached to this declaration.
|
|
RawComment getRawComment() const;
|
|
|
|
Optional<StringRef> getGroupName() const;
|
|
|
|
Optional<StringRef> getSourceFileName() const;
|
|
|
|
Optional<unsigned> getSourceOrder() const;
|
|
|
|
/// \returns the brief comment attached to this declaration.
|
|
StringRef getBriefComment() const;
|
|
|
|
/// \brief Returns true if there is a Clang AST node associated
|
|
/// with self.
|
|
bool hasClangNode() const {
|
|
return Bits.Decl.FromClang;
|
|
}
|
|
|
|
/// \brief 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();
|
|
}
|
|
|
|
/// \brief 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();
|
|
}
|
|
|
|
/// \brief 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();
|
|
}
|
|
|
|
/// \brief Return the GenericContext if the Decl has one.
|
|
LLVM_READONLY
|
|
const GenericContext *getAsGenericContext() const;
|
|
|
|
bool isPrivateStdlibDecl(bool treatNonBuiltinProtocolsAsPublic = true) const;
|
|
|
|
/// Whether this declaration is weak-imported.
|
|
bool isWeakImported(ModuleDecl *fromModule) const;
|
|
|
|
/// Returns true if the nature of this declaration allows overrides.
|
|
/// Note that this does not consider whether it is final or whether
|
|
/// the class it's on is final.
|
|
///
|
|
/// If this returns true, the decl can be safely casted to ValueDecl.
|
|
bool isPotentiallyOverridable() 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;
|
|
|
|
// Make vanilla new/delete illegal for Decls.
|
|
void *operator new(size_t Bytes) = delete;
|
|
void operator delete(void *Data) SWIFT_DELETE_OPERATOR_DELETED;
|
|
|
|
// Only allow allocation of Decls using the allocator in ASTContext
|
|
// or by doing a placement new.
|
|
void *operator new(size_t Bytes, const ASTContext &C,
|
|
unsigned Alignment = alignof(Decl));
|
|
void *operator new(size_t Bytes, void *Mem) {
|
|
assert(Mem);
|
|
return Mem;
|
|
}
|
|
};
|
|
|
|
/// \brief Use RAII to track Decl validation progress and non-reentrancy.
|
|
class DeclValidationRAII {
|
|
Decl *D;
|
|
|
|
public:
|
|
DeclValidationRAII(const DeclValidationRAII &) = delete;
|
|
DeclValidationRAII(DeclValidationRAII &&) = delete;
|
|
void operator =(const DeclValidationRAII &) = delete;
|
|
void operator =(DeclValidationRAII &&) = delete;
|
|
|
|
DeclValidationRAII(Decl *decl) : D(decl) {
|
|
D->setValidationState(Decl::ValidationState::Checking);
|
|
}
|
|
|
|
~DeclValidationRAII() {
|
|
D->setValidationState(Decl::ValidationState::Checked);
|
|
}
|
|
};
|
|
|
|
/// \brief 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;
|
|
}
|
|
|
|
enum class RequirementReprKind : unsigned {
|
|
/// A type bound T : P, where T is a type that depends on a generic
|
|
/// parameter and P is some type that should bound T, either as a concrete
|
|
/// supertype or a protocol to which T must conform.
|
|
TypeConstraint,
|
|
|
|
/// A same-type requirement T == U, where T and U are types that shall be
|
|
/// equivalent.
|
|
SameType,
|
|
|
|
/// A layout bound T : L, where T is a type that depends on a generic
|
|
/// parameter and L is some layout specification that should bound T.
|
|
LayoutConstraint,
|
|
|
|
// Note: there is code that packs this enum in a 2-bit bitfield. Audit users
|
|
// when adding enumerators.
|
|
};
|
|
|
|
/// \brief A single requirement in a 'where' clause, which places additional
|
|
/// restrictions on the generic parameters or associated types of a generic
|
|
/// function, type, or protocol.
|
|
///
|
|
/// This always represents a requirement spelled in the source code. It is
|
|
/// never generated implicitly.
|
|
///
|
|
/// \c GenericParamList assumes these are POD-like.
|
|
class RequirementRepr {
|
|
SourceLoc SeparatorLoc;
|
|
RequirementReprKind Kind : 2;
|
|
bool Invalid : 1;
|
|
TypeLoc FirstType;
|
|
|
|
/// The second element represents the right-hand side of the constraint.
|
|
/// It can be e.g. a type or a layout constraint.
|
|
union {
|
|
TypeLoc SecondType;
|
|
LayoutConstraintLoc SecondLayout;
|
|
};
|
|
|
|
/// Set during deserialization; used to print out the requirements accurately
|
|
/// for the generated interface.
|
|
StringRef AsWrittenString;
|
|
|
|
RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind,
|
|
TypeLoc FirstType, TypeLoc SecondType)
|
|
: SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false),
|
|
FirstType(FirstType), SecondType(SecondType) { }
|
|
|
|
RequirementRepr(SourceLoc SeparatorLoc, RequirementReprKind Kind,
|
|
TypeLoc FirstType, LayoutConstraintLoc SecondLayout)
|
|
: SeparatorLoc(SeparatorLoc), Kind(Kind), Invalid(false),
|
|
FirstType(FirstType), SecondLayout(SecondLayout) { }
|
|
|
|
void printImpl(ASTPrinter &OS, bool AsWritten) const;
|
|
|
|
public:
|
|
/// \brief Construct a new type-constraint requirement.
|
|
///
|
|
/// \param Subject The type that must conform to the given protocol or
|
|
/// composition, or be a subclass of the given class type.
|
|
/// \param ColonLoc The location of the ':', or an invalid location if
|
|
/// this requirement was implied.
|
|
/// \param Constraint The protocol or protocol composition to which the
|
|
/// subject must conform, or superclass from which the subject must inherit.
|
|
static RequirementRepr getTypeConstraint(TypeLoc Subject,
|
|
SourceLoc ColonLoc,
|
|
TypeLoc Constraint) {
|
|
return { ColonLoc, RequirementReprKind::TypeConstraint, Subject, Constraint };
|
|
}
|
|
|
|
/// \brief Construct a new same-type requirement.
|
|
///
|
|
/// \param FirstType The first type.
|
|
/// \param EqualLoc The location of the '==' in the same-type constraint, or
|
|
/// an invalid location if this requirement was implied.
|
|
/// \param SecondType The second type.
|
|
static RequirementRepr getSameType(TypeLoc FirstType,
|
|
SourceLoc EqualLoc,
|
|
TypeLoc SecondType) {
|
|
return { EqualLoc, RequirementReprKind::SameType, FirstType, SecondType };
|
|
}
|
|
|
|
/// \brief Construct a new layout-constraint requirement.
|
|
///
|
|
/// \param Subject The type that must conform to the given layout
|
|
/// requirement.
|
|
/// \param ColonLoc The location of the ':', or an invalid location if
|
|
/// this requirement was implied.
|
|
/// \param Layout The layout requirement to which the
|
|
/// subject must conform.
|
|
static RequirementRepr getLayoutConstraint(TypeLoc Subject,
|
|
SourceLoc ColonLoc,
|
|
LayoutConstraintLoc Layout) {
|
|
return {ColonLoc, RequirementReprKind::LayoutConstraint, Subject,
|
|
Layout};
|
|
}
|
|
|
|
/// \brief Determine the kind of requirement
|
|
RequirementReprKind getKind() const { return Kind; }
|
|
|
|
/// \brief Determine whether this requirement is invalid.
|
|
bool isInvalid() const { return Invalid; }
|
|
|
|
/// \brief Mark this requirement invalid.
|
|
void setInvalid() { Invalid = true; }
|
|
|
|
/// \brief For a type-bound requirement, return the subject of the
|
|
/// conformance relationship.
|
|
Type getSubject() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint ||
|
|
getKind() == RequirementReprKind::LayoutConstraint);
|
|
return FirstType.getType();
|
|
}
|
|
|
|
TypeRepr *getSubjectRepr() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint ||
|
|
getKind() == RequirementReprKind::LayoutConstraint);
|
|
return FirstType.getTypeRepr();
|
|
}
|
|
|
|
TypeLoc &getSubjectLoc() {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint ||
|
|
getKind() == RequirementReprKind::LayoutConstraint);
|
|
return FirstType;
|
|
}
|
|
|
|
const TypeLoc &getSubjectLoc() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint ||
|
|
getKind() == RequirementReprKind::LayoutConstraint);
|
|
return FirstType;
|
|
}
|
|
|
|
/// \brief For a type-bound requirement, return the protocol or to which
|
|
/// the subject conforms or superclass it inherits.
|
|
Type getConstraint() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint);
|
|
return SecondType.getType();
|
|
}
|
|
|
|
TypeRepr *getConstraintRepr() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint);
|
|
return SecondType.getTypeRepr();
|
|
}
|
|
|
|
TypeLoc &getConstraintLoc() {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint);
|
|
return SecondType;
|
|
}
|
|
|
|
const TypeLoc &getConstraintLoc() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint);
|
|
return SecondType;
|
|
}
|
|
|
|
LayoutConstraint getLayoutConstraint() const {
|
|
assert(getKind() == RequirementReprKind::LayoutConstraint);
|
|
return SecondLayout.getLayoutConstraint();
|
|
}
|
|
|
|
LayoutConstraintLoc &getLayoutConstraintLoc() {
|
|
assert(getKind() == RequirementReprKind::LayoutConstraint);
|
|
return SecondLayout;
|
|
}
|
|
|
|
const LayoutConstraintLoc &getLayoutConstraintLoc() const {
|
|
assert(getKind() == RequirementReprKind::LayoutConstraint);
|
|
return SecondLayout;
|
|
}
|
|
|
|
/// \brief Retrieve the location of the ':' in an explicitly-written
|
|
/// conformance requirement.
|
|
SourceLoc getColonLoc() const {
|
|
assert(getKind() == RequirementReprKind::TypeConstraint ||
|
|
getKind() == RequirementReprKind::LayoutConstraint);
|
|
return SeparatorLoc;
|
|
}
|
|
|
|
/// \brief Retrieve the first type of a same-type requirement.
|
|
Type getFirstType() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return FirstType.getType();
|
|
}
|
|
|
|
TypeRepr *getFirstTypeRepr() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return FirstType.getTypeRepr();
|
|
}
|
|
|
|
TypeLoc &getFirstTypeLoc() {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return FirstType;
|
|
}
|
|
|
|
const TypeLoc &getFirstTypeLoc() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return FirstType;
|
|
}
|
|
|
|
/// \brief Retrieve the second type of a same-type requirement.
|
|
Type getSecondType() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return SecondType.getType();
|
|
}
|
|
|
|
TypeRepr *getSecondTypeRepr() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return SecondType.getTypeRepr();
|
|
}
|
|
|
|
TypeLoc &getSecondTypeLoc() {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return SecondType;
|
|
}
|
|
|
|
const TypeLoc &getSecondTypeLoc() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return SecondType;
|
|
}
|
|
|
|
/// \brief Retrieve the location of the '==' in an explicitly-written
|
|
/// same-type requirement.
|
|
SourceLoc getEqualLoc() const {
|
|
assert(getKind() == RequirementReprKind::SameType);
|
|
return SeparatorLoc;
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
if (getKind() == RequirementReprKind::LayoutConstraint)
|
|
return SourceRange(FirstType.getSourceRange().Start,
|
|
SecondLayout.getSourceRange().End);
|
|
return SourceRange(FirstType.getSourceRange().Start,
|
|
SecondType.getSourceRange().End);
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_DEPRECATED(
|
|
void dump() const LLVM_ATTRIBUTE_USED,
|
|
"only for use within the debugger");
|
|
void print(raw_ostream &OS) const;
|
|
void print(ASTPrinter &Printer) const;
|
|
};
|
|
|
|
/// GenericParamList - A list of generic parameters that is part of a generic
|
|
/// function or type, along with extra requirements placed on those generic
|
|
/// parameters and types derived from them.
|
|
class GenericParamList final :
|
|
private llvm::TrailingObjects<GenericParamList, GenericTypeParamDecl *> {
|
|
friend TrailingObjects;
|
|
|
|
SourceRange Brackets;
|
|
unsigned NumParams;
|
|
SourceLoc WhereLoc;
|
|
MutableArrayRef<RequirementRepr> Requirements;
|
|
|
|
GenericParamList *OuterParameters;
|
|
|
|
SourceLoc TrailingWhereLoc;
|
|
unsigned FirstTrailingWhereArg;
|
|
|
|
GenericParamList(SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc WhereLoc,
|
|
MutableArrayRef<RequirementRepr> Requirements,
|
|
SourceLoc RAngleLoc);
|
|
|
|
// Don't copy.
|
|
GenericParamList(const GenericParamList &) = delete;
|
|
GenericParamList &operator=(const GenericParamList &) = delete;
|
|
|
|
public:
|
|
/// create - Create a new generic parameter list within the given AST context.
|
|
///
|
|
/// \param Context The ASTContext in which the generic parameter list will
|
|
/// be allocated.
|
|
/// \param LAngleLoc The location of the opening angle bracket ('<')
|
|
/// \param Params The list of generic parameters, which will be copied into
|
|
/// ASTContext-allocated memory.
|
|
/// \param RAngleLoc The location of the closing angle bracket ('>')
|
|
static GenericParamList *create(ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc RAngleLoc);
|
|
|
|
/// create - Create a new generic parameter list and "where" clause within
|
|
/// the given AST context.
|
|
///
|
|
/// \param Context The ASTContext in which the generic parameter list will
|
|
/// be allocated.
|
|
/// \param LAngleLoc The location of the opening angle bracket ('<')
|
|
/// \param Params The list of generic parameters, which will be copied into
|
|
/// ASTContext-allocated memory.
|
|
/// \param WhereLoc The location of the 'where' keyword, if any.
|
|
/// \param Requirements The list of requirements, which will be copied into
|
|
/// ASTContext-allocated memory.
|
|
/// \param RAngleLoc The location of the closing angle bracket ('>')
|
|
static GenericParamList *create(const ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc WhereLoc,
|
|
ArrayRef<RequirementRepr> Requirements,
|
|
SourceLoc RAngleLoc);
|
|
|
|
MutableArrayRef<GenericTypeParamDecl *> getParams() {
|
|
return {getTrailingObjects<GenericTypeParamDecl *>(), NumParams};
|
|
}
|
|
|
|
ArrayRef<GenericTypeParamDecl *> getParams() const {
|
|
return {getTrailingObjects<GenericTypeParamDecl *>(), NumParams};
|
|
}
|
|
|
|
using iterator = GenericTypeParamDecl **;
|
|
using const_iterator = const GenericTypeParamDecl * const *;
|
|
|
|
unsigned size() const { return NumParams; }
|
|
iterator begin() { return getParams().begin(); }
|
|
iterator end() { return getParams().end(); }
|
|
const_iterator begin() const { return getParams().begin(); }
|
|
const_iterator end() const { return getParams().end(); }
|
|
|
|
/// \brief Retrieve the location of the 'where' keyword, or an invalid
|
|
/// location if 'where' was not present.
|
|
SourceLoc getWhereLoc() const { return WhereLoc; }
|
|
|
|
/// \brief Retrieve the set of additional requirements placed on these
|
|
/// generic parameters and types derived from them.
|
|
///
|
|
/// This list may contain both explicitly-written requirements as well as
|
|
/// implicitly-generated requirements, and may be non-empty even if no
|
|
/// 'where' keyword is present.
|
|
MutableArrayRef<RequirementRepr> getRequirements() { return Requirements; }
|
|
|
|
/// \brief Retrieve the set of additional requirements placed on these
|
|
/// generic parameters and types derived from them.
|
|
///
|
|
/// This list may contain both explicitly-written requirements as well as
|
|
/// implicitly-generated requirements, and may be non-empty even if no
|
|
/// 'where' keyword is present.
|
|
ArrayRef<RequirementRepr> getRequirements() const { return Requirements; }
|
|
|
|
/// Retrieve only those requirements that are written within the brackets,
|
|
/// which does not include any requirements written in a trailing where
|
|
/// clause.
|
|
ArrayRef<RequirementRepr> getNonTrailingRequirements() const {
|
|
return Requirements.slice(0, FirstTrailingWhereArg);
|
|
}
|
|
|
|
/// Retrieve only those requirements written in a trailing where
|
|
/// clause.
|
|
ArrayRef<RequirementRepr> getTrailingRequirements() const {
|
|
return Requirements.slice(FirstTrailingWhereArg);
|
|
}
|
|
|
|
/// Determine whether the generic parameters have a trailing where clause.
|
|
bool hasTrailingWhereClause() const {
|
|
return FirstTrailingWhereArg < Requirements.size();
|
|
}
|
|
|
|
/// Add a trailing 'where' clause to the list of requirements.
|
|
///
|
|
/// Trailing where clauses are written outside the angle brackets, after the
|
|
/// main part of a declaration's signature.
|
|
void addTrailingWhereClause(ASTContext &ctx, SourceLoc trailingWhereLoc,
|
|
ArrayRef<RequirementRepr> trailingRequirements);
|
|
|
|
/// \brief Retrieve the outer generic parameter list, which provides the
|
|
/// generic parameters of the context in which this generic parameter list
|
|
/// exists.
|
|
///
|
|
/// Consider the following generic class:
|
|
///
|
|
/// \code
|
|
/// class Vector<T> {
|
|
/// init<R : Range where R.Element == T>(range : R) { }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// The generic parameter list <T> has no outer parameters, because it is
|
|
/// the outermost generic parameter list. The generic parameter list
|
|
/// <R : Range...> for the constructor has the generic parameter list <T> as
|
|
/// its outer generic parameter list.
|
|
GenericParamList *getOuterParameters() const { return OuterParameters; }
|
|
|
|
/// \brief Set the outer generic parameter list. See \c getOuterParameters
|
|
/// for more information.
|
|
void setOuterParameters(GenericParamList *Outer) { OuterParameters = Outer; }
|
|
|
|
SourceLoc getLAngleLoc() const { return Brackets.Start; }
|
|
SourceLoc getRAngleLoc() const { return Brackets.End; }
|
|
|
|
SourceRange getSourceRange() const { return Brackets; }
|
|
|
|
/// Retrieve the source range covering the where clause.
|
|
SourceRange getWhereClauseSourceRange() const {
|
|
if (WhereLoc.isInvalid())
|
|
return SourceRange();
|
|
|
|
auto endLoc = Requirements[FirstTrailingWhereArg-1].getSourceRange().End;
|
|
return SourceRange(WhereLoc, endLoc);
|
|
}
|
|
|
|
/// Retrieve the source range covering the trailing where clause.
|
|
SourceRange getTrailingWhereClauseSourceRange() const {
|
|
if (!hasTrailingWhereClause())
|
|
return SourceRange();
|
|
|
|
return SourceRange(TrailingWhereLoc,
|
|
Requirements.back().getSourceRange().End);
|
|
}
|
|
|
|
/// Retrieve the depth of this generic parameter list.
|
|
unsigned getDepth() const {
|
|
unsigned depth = 0;
|
|
for (auto gp = getOuterParameters(); gp; gp = gp->getOuterParameters())
|
|
++depth;
|
|
return depth;
|
|
}
|
|
|
|
/// Create a copy of the generic parameter list and all of its generic
|
|
/// parameter declarations. The copied generic parameters are re-parented
|
|
/// to the given DeclContext.
|
|
GenericParamList *clone(DeclContext *dc) const;
|
|
|
|
void print(raw_ostream &OS);
|
|
void dump();
|
|
};
|
|
|
|
/// A trailing where clause.
|
|
class alignas(RequirementRepr) TrailingWhereClause final :
|
|
private llvm::TrailingObjects<TrailingWhereClause, RequirementRepr> {
|
|
friend TrailingObjects;
|
|
|
|
SourceLoc WhereLoc;
|
|
|
|
/// The number of requirements. The actual requirements are tail-allocated.
|
|
unsigned NumRequirements;
|
|
|
|
TrailingWhereClause(SourceLoc whereLoc,
|
|
ArrayRef<RequirementRepr> requirements);
|
|
|
|
public:
|
|
/// Create a new trailing where clause with the given set of requirements.
|
|
static TrailingWhereClause *create(ASTContext &ctx, SourceLoc whereLoc,
|
|
ArrayRef<RequirementRepr> requirements);
|
|
|
|
/// Retrieve the location of the 'where' keyword.
|
|
SourceLoc getWhereLoc() const { return WhereLoc; }
|
|
|
|
/// Retrieve the set of requirements.
|
|
MutableArrayRef<RequirementRepr> getRequirements() {
|
|
return {getTrailingObjects<RequirementRepr>(), NumRequirements};
|
|
}
|
|
|
|
/// Retrieve the set of requirements.
|
|
ArrayRef<RequirementRepr> getRequirements() const {
|
|
return {getTrailingObjects<RequirementRepr>(), NumRequirements};
|
|
}
|
|
|
|
/// Compute the source range containing this trailing where clause.
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(WhereLoc,
|
|
getRequirements().back().getSourceRange().End);
|
|
}
|
|
};
|
|
|
|
// A private class for forcing exact field layout.
|
|
class _GenericContext {
|
|
// Not really public. See GenericContext.
|
|
public:
|
|
GenericParamList *GenericParams = nullptr;
|
|
|
|
/// 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 or environment of this declaration.
|
|
///
|
|
/// When this declaration stores only a signature, the generic
|
|
/// environment will be lazily loaded.
|
|
mutable llvm::PointerUnion<GenericSignature *, GenericEnvironment *>
|
|
GenericSigOrEnv;
|
|
};
|
|
|
|
class GenericContext : private _GenericContext, public DeclContext {
|
|
/// Lazily populate the generic environment.
|
|
GenericEnvironment *getLazyGenericEnvironmentSlow() const;
|
|
|
|
protected:
|
|
GenericContext(DeclContextKind Kind, DeclContext *Parent)
|
|
: _GenericContext(), DeclContext(Kind, Parent) { }
|
|
|
|
public:
|
|
/// \brief Retrieve the set of parameters to a generic context, or null if
|
|
/// this context is not generic.
|
|
GenericParamList *getGenericParams() const { return GenericParams; }
|
|
|
|
void setGenericParams(GenericParamList *GenericParams);
|
|
|
|
/// \brief Determine whether this context has generic parameters
|
|
/// of its own.
|
|
bool isGeneric() const { return GenericParams != nullptr; }
|
|
|
|
/// 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.
|
|
TypeArrayView<GenericTypeParamType> getInnermostGenericParamTypes() const;
|
|
|
|
/// Retrieve the generic requirements.
|
|
ArrayRef<Requirement> getGenericRequirements() const;
|
|
|
|
/// Set a lazy generic environment.
|
|
void setLazyGenericEnvironment(LazyMemberLoader *lazyLoader,
|
|
GenericSignature *genericSig,
|
|
uint64_t genericEnvData);
|
|
|
|
/// Whether this generic context has a lazily-created generic environment
|
|
/// that has not yet been constructed.
|
|
bool hasLazyGenericEnvironment() const;
|
|
|
|
/// Set the generic context of this context.
|
|
void setGenericEnvironment(GenericEnvironment *genericEnv);
|
|
|
|
/// Retrieve the position of any where clause for this context's
|
|
/// generic parameters.
|
|
SourceRange getGenericTrailingWhereClauseSourceRange() const;
|
|
};
|
|
static_assert(sizeof(_GenericContext) + sizeof(DeclContext) ==
|
|
sizeof(GenericContext), "Please add fields to _GenericContext");
|
|
|
|
/// Describes what kind of name is being imported.
|
|
///
|
|
/// If the enumerators here are changed, make sure to update all diagnostics
|
|
/// using ImportKind as a select index.
|
|
enum class ImportKind : uint8_t {
|
|
Module = 0,
|
|
Type,
|
|
Struct,
|
|
Class,
|
|
Enum,
|
|
Protocol,
|
|
Var,
|
|
Func
|
|
};
|
|
|
|
/// ImportDecl - This represents a single import declaration, e.g.:
|
|
/// import Swift
|
|
/// import typealias Swift.Int
|
|
class ImportDecl final : public Decl,
|
|
private llvm::TrailingObjects<ImportDecl, std::pair<Identifier,SourceLoc>> {
|
|
friend TrailingObjects;
|
|
|
|
public:
|
|
typedef std::pair<Identifier, SourceLoc> AccessPathElement;
|
|
|
|
private:
|
|
SourceLoc ImportLoc;
|
|
SourceLoc KindLoc;
|
|
|
|
/// The resolved module.
|
|
ModuleDecl *Mod = nullptr;
|
|
/// The resolved decls if this is a decl import.
|
|
ArrayRef<ValueDecl *> Decls;
|
|
|
|
ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
|
|
SourceLoc KindLoc, ArrayRef<AccessPathElement> Path);
|
|
|
|
public:
|
|
static ImportDecl *create(ASTContext &C, DeclContext *DC,
|
|
SourceLoc ImportLoc, ImportKind Kind,
|
|
SourceLoc KindLoc,
|
|
ArrayRef<AccessPathElement> 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 Optional<ImportKind> findBestImportKind(ArrayRef<ValueDecl *> Decls);
|
|
|
|
ArrayRef<AccessPathElement> getFullAccessPath() const {
|
|
return {getTrailingObjects<AccessPathElement>(),
|
|
Bits.ImportDecl.NumPathElements};
|
|
}
|
|
|
|
ArrayRef<AccessPathElement> getModulePath() const {
|
|
auto result = getFullAccessPath();
|
|
if (getImportKind() != ImportKind::Module)
|
|
result = result.slice(0, result.size()-1);
|
|
return result;
|
|
}
|
|
|
|
ArrayRef<AccessPathElement> getDeclPath() const {
|
|
if (getImportKind() == ImportKind::Module)
|
|
return {};
|
|
return getFullAccessPath().back();
|
|
}
|
|
|
|
ImportKind getImportKind() const {
|
|
return static_cast<ImportKind>(Bits.ImportDecl.ImportKind);
|
|
}
|
|
|
|
bool isExported() const {
|
|
return getAttrs().hasAttribute<ExportedAttr>();
|
|
}
|
|
|
|
ModuleDecl *getModule() const { return Mod; }
|
|
void setModule(ModuleDecl *M) { Mod = M; }
|
|
|
|
ArrayRef<ValueDecl *> getDecls() const { return Decls; }
|
|
void setDecls(ArrayRef<ValueDecl *> Ds) { Decls = Ds; }
|
|
|
|
const clang::Module *getClangModule() const {
|
|
return getClangNode().getClangModule();
|
|
}
|
|
|
|
SourceLoc getStartLoc() const { return ImportLoc; }
|
|
SourceLoc getLoc() const { return getFullAccessPath().front().second; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(ImportLoc, getFullAccessPath().back().second);
|
|
}
|
|
SourceLoc getKindLoc() const { return KindLoc; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Import;
|
|
}
|
|
};
|
|
|
|
/// 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.
|
|
TypeLoc ExtendedType;
|
|
|
|
MutableArrayRef<TypeLoc> Inherited;
|
|
|
|
/// \brief 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;
|
|
|
|
ExtensionDecl(SourceLoc extensionLoc, TypeLoc extendedType,
|
|
MutableArrayRef<TypeLoc> 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();
|
|
|
|
public:
|
|
using Decl::getASTContext;
|
|
|
|
/// Create a new extension declaration.
|
|
static ExtensionDecl *create(ASTContext &ctx, SourceLoc extensionLoc,
|
|
TypeLoc extendedType,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause,
|
|
ClangNode clangNode = ClangNode());
|
|
|
|
SourceLoc getStartLoc() const { return ExtensionLoc; }
|
|
SourceLoc getLoc() const { return ExtensionLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return { ExtensionLoc, Braces.End };
|
|
}
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
/// Retrieve the type being extended.
|
|
Type getExtendedType() const { return ExtendedType.getType(); }
|
|
|
|
/// Retrieve the extended type location.
|
|
TypeLoc &getExtendedTypeLoc() { return ExtendedType; }
|
|
|
|
/// Retrieve the extended type location.
|
|
const TypeLoc &getExtendedTypeLoc() const { return ExtendedType; }
|
|
|
|
/// \brief Retrieve the set of protocols that this type inherits (i.e,
|
|
/// explicitly conforms to).
|
|
MutableArrayRef<TypeLoc> getInherited() { return Inherited; }
|
|
ArrayRef<TypeLoc> getInherited() const { return Inherited; }
|
|
|
|
void setInherited(MutableArrayRef<TypeLoc> i) { Inherited = i; }
|
|
|
|
/// Retrieve one of the types listed in the "inherited" clause.
|
|
Type getInheritedType(unsigned index) const;
|
|
|
|
/// Whether we have fully checked the extension signature.
|
|
bool hasValidSignature() const {
|
|
return getValidationState() > ValidationState::CheckingWithValidSignature;
|
|
}
|
|
|
|
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;
|
|
|
|
// 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->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
return C->getIterableContextKind()
|
|
== IterableDeclContextKind::ExtensionDecl;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
};
|
|
|
|
/// \brief 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;
|
|
}
|
|
};
|
|
|
|
/// \brief 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 {
|
|
Pattern *ThePattern;
|
|
|
|
/// The location of the equal '=' token.
|
|
SourceLoc EqualLoc;
|
|
|
|
enum class Flags {
|
|
Checked = 1 << 0,
|
|
Removed = 1 << 1,
|
|
Lazy = 1 << 2,
|
|
};
|
|
|
|
// When the initializer is removed we don't actually clear the pointer
|
|
// because we might need to get initializer's source range. Since the
|
|
// initializer is ASTContext-allocated it is safe.
|
|
llvm::PointerIntPair<Expr *, 3, OptionSet<Flags>> InitAndFlags;
|
|
|
|
/// The initializer context used for this pattern binding entry.
|
|
DeclContext *InitContext = nullptr;
|
|
|
|
friend class PatternBindingInitializer;
|
|
|
|
public:
|
|
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
|
|
DeclContext *InitContext)
|
|
: ThePattern(P), EqualLoc(EqualLoc), InitAndFlags(E, {}),
|
|
InitContext(InitContext) {}
|
|
|
|
Pattern *getPattern() const { return ThePattern; }
|
|
void setPattern(Pattern *P) { ThePattern = P; }
|
|
Expr *getInit() const {
|
|
return (InitAndFlags.getInt().contains(Flags::Removed))
|
|
? nullptr : InitAndFlags.getPointer();
|
|
}
|
|
Expr *getNonLazyInit() const {
|
|
return isInitializerLazy() ? nullptr : getInit();
|
|
}
|
|
SourceRange getOrigInitRange() const;
|
|
void setInit(Expr *E);
|
|
|
|
/// Retrieve the location of the equal '=' token.
|
|
SourceLoc getEqualLoc() const { return EqualLoc; }
|
|
|
|
/// Set the location of the equal '=' token.
|
|
void setEqualLoc(SourceLoc equalLoc) { EqualLoc = equalLoc; }
|
|
|
|
/// Retrieve the initializer as it was written in the source.
|
|
Expr *getInitAsWritten() const { return InitAndFlags.getPointer(); }
|
|
|
|
bool isInitializerChecked() const {
|
|
return InitAndFlags.getInt().contains(Flags::Checked);
|
|
}
|
|
void setInitializerChecked() {
|
|
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Checked);
|
|
}
|
|
|
|
bool isInitializerLazy() const {
|
|
return InitAndFlags.getInt().contains(Flags::Lazy);
|
|
}
|
|
void setInitializerLazy() {
|
|
InitAndFlags.setInt(InitAndFlags.getInt() | Flags::Lazy);
|
|
}
|
|
|
|
// Return the first variable initialized by this pattern.
|
|
VarDecl *getAnchoringVarDecl() const;
|
|
|
|
// Retrieve the declaration context for the initializer.
|
|
DeclContext *getInitContext() const { return InitContext; }
|
|
|
|
/// Override the initializer context.
|
|
void setInitContext(DeclContext *dc) { InitContext = dc; }
|
|
|
|
/// Retrieve the source range covered by this pattern binding.
|
|
///
|
|
/// \param omitAccessors Whether the computation should omit the accessors
|
|
/// from the source range.
|
|
SourceRange getSourceRange(bool omitAccessors = false) const;
|
|
};
|
|
|
|
/// \brief 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;
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() ? StaticLoc : VarLoc;
|
|
}
|
|
SourceLoc getLoc() const { return VarLoc; }
|
|
SourceRange getSourceRange() const;
|
|
|
|
unsigned getNumPatternEntries() const {
|
|
return Bits.PatternBindingDecl.NumPatternEntries;
|
|
}
|
|
|
|
ArrayRef<PatternBindingEntry> getPatternList() const {
|
|
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
|
|
}
|
|
|
|
Expr *getInit(unsigned i) const {
|
|
return getPatternList()[i].getInit();
|
|
}
|
|
Expr *getNonLazyInit(unsigned i) const {
|
|
return getPatternList()[i].getNonLazyInit();
|
|
}
|
|
|
|
SourceRange getOrigInitRange(unsigned i) const {
|
|
return getPatternList()[i].getOrigInitRange();
|
|
}
|
|
|
|
void setInit(unsigned i, Expr *E) {
|
|
getMutablePatternList()[i].setInit(E);
|
|
}
|
|
|
|
Pattern *getPattern(unsigned i) const {
|
|
return getPatternList()[i].getPattern();
|
|
}
|
|
|
|
void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext);
|
|
|
|
/// 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;
|
|
|
|
/// Return the PatternEntry (a pattern + initializer pair) for the specified
|
|
/// VarDecl.
|
|
PatternBindingEntry getPatternEntryForVarDecl(const VarDecl *VD) const {
|
|
return getPatternList()[getPatternEntryIndexForVarDecl(VD)];
|
|
}
|
|
|
|
bool isInitializerChecked(unsigned i) const {
|
|
return getPatternList()[i].isInitializerChecked();
|
|
}
|
|
|
|
void setInitializerChecked(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerChecked();
|
|
}
|
|
|
|
bool isInitializerLazy(unsigned i) const {
|
|
return getPatternList()[i].isInitializerLazy();
|
|
}
|
|
|
|
void setInitializerLazy(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerLazy();
|
|
}
|
|
|
|
/// 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.
|
|
///
|
|
/// This is only valid to check for bindings which have storage.
|
|
bool isDefaultInitializable() const {
|
|
assert(hasStorage());
|
|
|
|
for (unsigned i = 0, e = getNumPatternEntries(); i < e; ++i)
|
|
if (!isDefaultInitializable(i))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Can the pattern at index i be default initialized?
|
|
bool isDefaultInitializable(unsigned i) const;
|
|
|
|
/// When the pattern binding contains only a single variable with no
|
|
/// destructuring, retrieve that variable.
|
|
VarDecl *getSingleVar() 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;
|
|
|
|
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;
|
|
|
|
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;
|
|
SourceLoc getLoc() const { return getStartLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::TopLevelCode;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
};
|
|
|
|
/// 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 SerializedLocalDeclContext {
|
|
public:
|
|
SerializedTopLevelCodeDeclContext(DeclContext *Parent)
|
|
: SerializedLocalDeclContext(LocalDeclContextKind::TopLevelCodeDecl,
|
|
Parent) {}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto LDC = dyn_cast<SerializedLocalDeclContext>(DC))
|
|
return LDC->getLocalDeclContextKind() ==
|
|
LocalDeclContextKind::TopLevelCodeDecl;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// IfConfigDecl - This class represents #if/#else/#endif blocks.
|
|
/// Active and inactive block members are stored separately, with the intention
|
|
/// being that active members will be handed back to the enclosing context.
|
|
class IfConfigDecl : public Decl {
|
|
/// An array of clauses controlling each of the #if/#elseif/#else conditions.
|
|
/// The array is ASTContext allocated.
|
|
ArrayRef<IfConfigClause> Clauses;
|
|
SourceLoc EndLoc;
|
|
public:
|
|
|
|
IfConfigDecl(DeclContext *Parent, ArrayRef<IfConfigClause> Clauses,
|
|
SourceLoc EndLoc, bool HadMissingEnd)
|
|
: Decl(DeclKind::IfConfig, Parent), Clauses(Clauses), EndLoc(EndLoc)
|
|
{
|
|
Bits.IfConfigDecl.HadMissingEnd = HadMissingEnd;
|
|
}
|
|
|
|
ArrayRef<IfConfigClause> getClauses() const { return Clauses; }
|
|
|
|
/// Return the active clause, or null if there is no active one.
|
|
const IfConfigClause *getActiveClause() const {
|
|
for (auto &Clause : Clauses)
|
|
if (Clause.isActive) return &Clause;
|
|
return nullptr;
|
|
}
|
|
|
|
const ArrayRef<ASTNode> getActiveClauseElements() const {
|
|
if (auto *Clause = getActiveClause())
|
|
return Clause->Elements;
|
|
return {};
|
|
}
|
|
|
|
SourceLoc getEndLoc() const { return EndLoc; }
|
|
SourceLoc getLoc() const { return Clauses[0].Loc; }
|
|
|
|
bool hadMissingEnd() const { return Bits.IfConfigDecl.HadMissingEnd; }
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::IfConfig;
|
|
}
|
|
};
|
|
|
|
class StringLiteralExpr;
|
|
|
|
class PoundDiagnosticDecl : public Decl {
|
|
SourceLoc StartLoc;
|
|
SourceLoc EndLoc;
|
|
StringLiteralExpr *Message;
|
|
|
|
public:
|
|
PoundDiagnosticDecl(DeclContext *Parent, bool IsError, SourceLoc StartLoc,
|
|
SourceLoc EndLoc, StringLiteralExpr *Message)
|
|
: Decl(DeclKind::PoundDiagnostic, Parent), StartLoc(StartLoc),
|
|
EndLoc(EndLoc), Message(Message) {
|
|
Bits.PoundDiagnosticDecl.IsError = IsError;
|
|
Bits.PoundDiagnosticDecl.HasBeenEmitted = false;
|
|
}
|
|
|
|
DiagnosticKind getKind() {
|
|
return isError() ? DiagnosticKind::Error : DiagnosticKind::Warning;
|
|
}
|
|
|
|
StringLiteralExpr *getMessage() { return Message; }
|
|
|
|
bool isError() {
|
|
return Bits.PoundDiagnosticDecl.IsError;
|
|
}
|
|
|
|
bool hasBeenEmitted() {
|
|
return Bits.PoundDiagnosticDecl.HasBeenEmitted;
|
|
}
|
|
|
|
void markEmitted() {
|
|
Bits.PoundDiagnosticDecl.HasBeenEmitted = true;
|
|
}
|
|
|
|
SourceLoc getEndLoc() const { return EndLoc; };
|
|
SourceLoc getLoc() const { return StartLoc; }
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(StartLoc, EndLoc);
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PoundDiagnostic;
|
|
}
|
|
};
|
|
|
|
/// ValueDecl - All named decls that are values in the language. These can
|
|
/// have a type, etc.
|
|
class ValueDecl : public Decl {
|
|
DeclName Name;
|
|
SourceLoc NameLoc;
|
|
llvm::PointerIntPair<Type, 3, OptionalEnum<AccessLevel>> TypeAndAccess;
|
|
unsigned LocalDiscriminator = 0;
|
|
|
|
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;
|
|
} LazySemanticInfo;
|
|
|
|
friend class OverriddenDeclsRequest;
|
|
friend class IsObjCRequest;
|
|
friend class IsDynamicRequest;
|
|
|
|
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;
|
|
LazySemanticInfo.isObjCComputed = false;
|
|
LazySemanticInfo.isObjC = false;
|
|
LazySemanticInfo.hasOverriddenComputed = false;
|
|
LazySemanticInfo.hasOverridden = false;
|
|
LazySemanticInfo.isDynamicComputed = false;
|
|
LazySemanticInfo.isDynamic = 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;
|
|
}
|
|
|
|
public:
|
|
/// \brief Return true if this protocol member is a protocol requirement.
|
|
///
|
|
/// Asserts if this is not a member of a protocol.
|
|
bool isProtocolRequirement() const;
|
|
|
|
/// 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(bool checked) {
|
|
Bits.ValueDecl.CheckedRedeclaration = checked;
|
|
}
|
|
|
|
void setUserAccessible(bool Accessible) {
|
|
Bits.ValueDecl.IsUserAccessible = Accessible;
|
|
}
|
|
|
|
bool isUserAccessible() const {
|
|
return Bits.ValueDecl.IsUserAccessible;
|
|
}
|
|
|
|
bool hasName() const { return bool(Name); }
|
|
bool isOperator() const { return Name.isOperator(); }
|
|
|
|
/// Retrieve the full name of the declaration.
|
|
/// TODO: Rename to getName?
|
|
DeclName getFullName() 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(); }
|
|
|
|
/// 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.
|
|
Optional<ObjCSelector> getObjCRuntimeName() 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; }
|
|
SourceLoc getLoc() const { return NameLoc; }
|
|
|
|
bool isUsableFromInline() 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.
|
|
///
|
|
/// This is the access 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.
|
|
///
|
|
/// 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 getFormalAccessScope
|
|
AccessLevel getFormalAccess(const DeclContext *useDC = nullptr,
|
|
bool treatUsableFromInlineAsPublic = false) const;
|
|
|
|
/// If this declaration is a member of a protocol extension, return the
|
|
/// minimum of the given access level and the protocol's access level.
|
|
///
|
|
/// Otherwise, return the given access level unmodified.
|
|
///
|
|
/// This is used when checking name lookup visibility. Protocol extension
|
|
/// members can be found when performing name lookup on a concrete type;
|
|
/// if the concrete type is visible from the lookup context but the
|
|
/// protocol is not, we do not want the protocol extension members to be
|
|
/// visible.
|
|
AccessLevel adjustAccessLevelForProtocolExtension(AccessLevel access) const;
|
|
|
|
/// Determine whether this Decl has either Private or FilePrivate access.
|
|
bool isOutermostPrivateOrFilePrivateScope() 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
|
|
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) 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);
|
|
|
|
bool hasValidSignature() const;
|
|
|
|
/// isSettable - Determine whether references to this decl may appear
|
|
/// on the left-hand side of an assignment or as the operand of a
|
|
/// `&` or 'inout' operator.
|
|
bool isSettable(const DeclContext *UseDC,
|
|
const DeclRefExpr *base = nullptr) const;
|
|
|
|
/// 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);
|
|
|
|
/// Retrieve the declaration that this declaration overrides, if any.
|
|
ValueDecl *getOverriddenDecl() 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 marked with 'final'?
|
|
bool isFinal() const {
|
|
return getAttrs().hasAttribute<FinalAttr>();
|
|
}
|
|
|
|
/// Is this declaration marked with 'dynamic'?
|
|
bool isDynamic() 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 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;
|
|
|
|
/// 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.
|
|
void dumpRef() const;
|
|
|
|
/// 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;
|
|
|
|
/// Retrieve the location at which we should insert a new attribute or
|
|
/// modifier.
|
|
SourceLoc getAttributeInsertionLoc(bool forModifier) 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;
|
|
};
|
|
|
|
/// This is a common base class for declarations which declare a type.
|
|
class TypeDecl : public ValueDecl {
|
|
MutableArrayRef<TypeLoc> Inherited;
|
|
|
|
protected:
|
|
TypeDecl(DeclKind K, llvm::PointerUnion<DeclContext *, ASTContext *> context,
|
|
Identifier name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> inherited) :
|
|
ValueDecl(K, context, name, NameLoc), Inherited(inherited) {}
|
|
|
|
public:
|
|
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getFullName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseName().getIdentifier().str() : "_";
|
|
}
|
|
|
|
/// The type of this declaration's values. For the type of the
|
|
/// declaration itself, use getInterfaceType(), which returns a
|
|
/// metatype.
|
|
Type getDeclaredInterfaceType() const;
|
|
|
|
/// \brief Retrieve the set of protocols that this type inherits (i.e,
|
|
/// explicitly conforms to).
|
|
MutableArrayRef<TypeLoc> getInherited() { return Inherited; }
|
|
ArrayRef<TypeLoc> getInherited() const { return Inherited; }
|
|
|
|
/// Retrieve one of the types listed in the "inherited" clause.
|
|
Type getInheritedType(unsigned index) const;
|
|
|
|
void setInherited(MutableArrayRef<TypeLoc> i) { Inherited = i; }
|
|
|
|
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 can 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,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
GenericParamList *GenericParams);
|
|
|
|
// Resolve ambiguity due to multiple base classes.
|
|
using TypeDecl::getASTContext;
|
|
using DeclContext::operator new;
|
|
using TypeDecl::getDeclaredInterfaceType;
|
|
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_GenericTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_GenericTypeDecl;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/// TypeAliasDecl - This is a declaration of a typealias, for example:
|
|
///
|
|
/// typealias Foo = Int
|
|
///
|
|
/// TypeAliasDecl's always have 'MetatypeType' type.
|
|
///
|
|
class TypeAliasDecl : public GenericTypeDecl {
|
|
/// The location of the 'typealias' keyword
|
|
SourceLoc TypeAliasLoc;
|
|
|
|
/// The location of the equal '=' token
|
|
SourceLoc EqualLoc;
|
|
|
|
/// 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;
|
|
}
|
|
|
|
TypeLoc &getUnderlyingTypeLoc() {
|
|
return UnderlyingTy;
|
|
}
|
|
const TypeLoc &getUnderlyingTypeLoc() const {
|
|
return UnderlyingTy;
|
|
}
|
|
|
|
/// Set the underlying type, for deserialization and synthesized
|
|
/// aliases.
|
|
void setUnderlyingType(Type type);
|
|
|
|
/// For generic typealiases, return the unbound generic type.
|
|
UnboundGenericType *getUnboundGenericType() const;
|
|
|
|
bool isCompatibilityAlias() const {
|
|
return Bits.TypeAliasDecl.IsCompatibilityAlias;
|
|
}
|
|
|
|
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->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// Abstract class describing generic type parameters and associated types,
|
|
/// whose common purpose is to anchor the abstract type parameter and specify
|
|
/// requirements for any corresponding type argument.
|
|
class AbstractTypeParamDecl : public TypeDecl {
|
|
protected:
|
|
AbstractTypeParamDecl(DeclKind kind, DeclContext *dc, Identifier name,
|
|
SourceLoc NameLoc)
|
|
: TypeDecl(kind, dc, name, NameLoc, { }) { }
|
|
|
|
public:
|
|
/// Return the superclass of the generic parameter.
|
|
Type getSuperclass() const;
|
|
|
|
/// Retrieve the set of protocols to which this abstract type
|
|
/// parameter conforms.
|
|
ArrayRef<ProtocolDecl *> getConformingProtocols() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_AbstractTypeParamDecl &&
|
|
D->getKind() <= DeclKind::Last_AbstractTypeParamDecl;
|
|
}
|
|
};
|
|
|
|
/// 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 : public AbstractTypeParamDecl {
|
|
public:
|
|
static const unsigned InvalidDepth = 0xFFFF;
|
|
|
|
/// 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.
|
|
GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc,
|
|
unsigned depth, unsigned index);
|
|
|
|
/// 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 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; }
|
|
|
|
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
|
|
///
|
|
/// Every protocol has an implicitly-created associated type 'Self' that
|
|
/// describes a type that conforms to the protocol.
|
|
class AssociatedTypeDecl : public AbstractTypeParamDecl {
|
|
/// The location of the initial keyword.
|
|
SourceLoc KeywordLoc;
|
|
|
|
/// The default definition.
|
|
TypeLoc DefaultDefinition;
|
|
|
|
/// The where clause attached to the associated type.
|
|
TrailingWhereClause *TrailingWhere;
|
|
|
|
LazyMemberLoader *Resolver = nullptr;
|
|
uint64_t ResolverContextData;
|
|
|
|
public:
|
|
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc, TypeLoc defaultDefinition,
|
|
TrailingWhereClause *trailingWhere);
|
|
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc, TrailingWhereClause *trailingWhere,
|
|
LazyMemberLoader *definitionResolver,
|
|
uint64_t resolverData);
|
|
|
|
/// Get the protocol in which this associated type is declared.
|
|
ProtocolDecl *getProtocol() const {
|
|
return cast<ProtocolDecl>(getDeclContext());
|
|
}
|
|
|
|
/// Retrieve the default definition type.
|
|
Type getDefaultDefinitionType() const {
|
|
return getDefaultDefinitionLoc().getType();
|
|
}
|
|
|
|
TypeLoc &getDefaultDefinitionLoc();
|
|
const TypeLoc &getDefaultDefinitionLoc() const {
|
|
return const_cast<AssociatedTypeDecl *>(this)->getDefaultDefinitionLoc();
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Set the interface type of this associated type declaration to a dependen
|
|
/// member type of 'Self'.
|
|
void computeType();
|
|
|
|
/// 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>(
|
|
AbstractTypeParamDecl::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 ConformanceLookupTable;
|
|
|
|
/// Kinds of optional types.
|
|
enum OptionalTypeKind : unsigned {
|
|
/// The type is not an optional type.
|
|
OTK_None = 0,
|
|
|
|
/// The type is Optional<T>.
|
|
OTK_Optional,
|
|
|
|
/// The type is ImplicitlyUnwrappedOptional<T>.
|
|
OTK_ImplicitlyUnwrappedOptional
|
|
};
|
|
enum { NumOptionalTypeKinds = 2 };
|
|
|
|
// 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.");
|
|
}
|
|
|
|
/// NominalTypeDecl - a declaration of a nominal type, like a struct.
|
|
class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
|
|
SourceRange Braces;
|
|
|
|
/// \brief The first extension of this type.
|
|
ExtensionDecl *FirstExtension = nullptr;
|
|
|
|
/// \brief The last extension of this type, used solely for efficient
|
|
/// insertion of new extensions.
|
|
ExtensionDecl *LastExtension = nullptr;
|
|
|
|
/// \brief 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();
|
|
|
|
/// \brief A lookup table containing all of the members of this type and
|
|
/// its extensions.
|
|
///
|
|
/// The table itself is lazily constructed and updated when
|
|
/// lookupDirect() is called. The bit indicates whether the lookup
|
|
/// table has already added members by walking the declarations in
|
|
/// scope.
|
|
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;
|
|
|
|
/// Prepare the lookup table to make it ready for lookups.
|
|
void prepareLookupTable(bool ignoreNewExtensions);
|
|
|
|
/// 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);
|
|
|
|
/// \brief 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;
|
|
|
|
friend class ASTContext;
|
|
friend class MemberLookupTable;
|
|
friend class ConformanceLookupTable;
|
|
friend class ExtensionDecl;
|
|
friend class DeclContext;
|
|
friend class IterableDeclContext;
|
|
friend ArrayRef<ValueDecl *>
|
|
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const;
|
|
|
|
protected:
|
|
Type DeclaredTy;
|
|
Type DeclaredTyInContext;
|
|
Type DeclaredInterfaceTy;
|
|
|
|
NominalTypeDecl(DeclKind K, DeclContext *DC, Identifier name,
|
|
SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
GenericParamList *GenericParams) :
|
|
GenericTypeDecl(K, DC, name, NameLoc, inherited, GenericParams),
|
|
IterableDeclContext(IterableDeclContextKind::NominalTypeDecl)
|
|
{
|
|
setGenericParams(GenericParams);
|
|
Bits.NominalTypeDecl.AddedImplicitInitializers = false;
|
|
ExtensionGeneration = 0;
|
|
Bits.NominalTypeDecl.HasLazyConformances = false;
|
|
Bits.NominalTypeDecl.HasValidatedLayout = false;
|
|
}
|
|
|
|
friend class ProtocolType;
|
|
|
|
public:
|
|
using GenericTypeDecl::getASTContext;
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
/// \brief Should this declaration behave as if it must be accessed
|
|
/// resiliently, even when we're building a non-resilient module?
|
|
///
|
|
/// This is used for diagnostics, because we do not want a behavior
|
|
/// change between builds with resilience enabled and disabled.
|
|
bool isFormallyResilient() const;
|
|
|
|
/// \brief Do we need to use resilient access patterns outside of this type's
|
|
/// resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// \brief Do we need to use resilient access patterns when accessing this
|
|
/// type from the given module?
|
|
bool isResilient(ModuleDecl *M, 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;
|
|
}
|
|
|
|
/// Determine whether we have already validated any members
|
|
/// which affect layout.
|
|
bool hasValidatedLayout() const {
|
|
return Bits.NominalTypeDecl.HasValidatedLayout;
|
|
}
|
|
|
|
/// Note that we have attempted to validate any members
|
|
/// which affect layout.
|
|
void setHasValidatedLayout() {
|
|
Bits.NominalTypeDecl.HasValidatedLayout = true;
|
|
}
|
|
|
|
/// Set the interface type of this nominal type to the metatype of the
|
|
/// declared interface type.
|
|
void computeType();
|
|
|
|
/// getDeclaredType - Retrieve the type declared by this entity, without
|
|
/// any generic parameters bound if this is a generic type.
|
|
Type getDeclaredType() const;
|
|
|
|
/// getDeclaredTypeInContext - Retrieve the type declared by this entity, with
|
|
/// context archetypes bound if this is a generic type.
|
|
Type getDeclaredTypeInContext() const;
|
|
|
|
/// getDeclaredInterfaceType - Retrieve the type declared by this entity, with
|
|
/// generic parameters bound if this is a generic type.
|
|
Type getDeclaredInterfaceType() const;
|
|
|
|
/// \brief Add a new extension to this nominal type.
|
|
void addExtension(ExtensionDecl *extension);
|
|
|
|
/// \brief Retrieve the set of extensions of this type.
|
|
ExtensionRange getExtensions();
|
|
|
|
/// Make a member of this nominal type, or one of its extensions,
|
|
/// immediately visible in the lookup table.
|
|
///
|
|
/// A member of a nominal type or extension thereof will become
|
|
/// visible to name lookup as soon as it is added. However, if the
|
|
/// addition of a member is delayed---for example, because it's
|
|
/// being introduced in response to name lookup---this method can be
|
|
/// called to make it immediately visible.
|
|
void makeMemberVisible(ValueDecl *member);
|
|
|
|
/// 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.
|
|
///
|
|
/// \param ignoreNewExtensions Whether to avoid loading any new extension.
|
|
/// Used by the module loader to break recursion.
|
|
TinyPtrVector<ValueDecl *> lookupDirect(DeclName name,
|
|
bool ignoreNewExtensions = false);
|
|
|
|
/// 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 module The module from which we initiate the search.
|
|
/// FIXME: This is currently unused.
|
|
///
|
|
/// \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(
|
|
ModuleDecl *module, ProtocolDecl *protocol,
|
|
SmallVectorImpl<ProtocolConformance *> &conformances) const;
|
|
|
|
/// Retrieve all of the protocols that this nominal type conforms to.
|
|
SmallVector<ProtocolDecl *, 2> getAllProtocols() 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(ProtocolConformance *conformance);
|
|
|
|
void setConformanceLoader(LazyMemberLoader *resolver, uint64_t contextData);
|
|
|
|
/// Is this the decl for Optional<T>?
|
|
bool isOptionalDecl() const;
|
|
|
|
private:
|
|
/// Predicate used to filter StoredPropertyRange.
|
|
struct ToStoredProperty {
|
|
ToStoredProperty(bool skipInaccessible = false) :
|
|
skipUserInaccessible(skipInaccessible) {}
|
|
bool skipUserInaccessible;
|
|
Optional<VarDecl *> operator()(Decl *decl) const;
|
|
};
|
|
|
|
public:
|
|
/// A range for iterating the stored member variables of a structure.
|
|
using StoredPropertyRange = OptionalTransformRange<DeclRange,
|
|
ToStoredProperty>;
|
|
|
|
/// Return a collection of the stored member variables of this type.
|
|
StoredPropertyRange getStoredProperties(bool skipInaccessible = false) const {
|
|
return StoredPropertyRange(getMembers(),
|
|
ToStoredProperty(skipInaccessible));
|
|
}
|
|
|
|
private:
|
|
/// Predicate used to filter StoredPropertyRange.
|
|
struct ToStoredPropertyOrMissingMemberPlaceholder {
|
|
Optional<Decl *> operator()(Decl *decl) const;
|
|
};
|
|
|
|
public:
|
|
/// A range for iterating the stored member variables of a structure.
|
|
using StoredPropertyOrMissingMemberPlaceholderRange
|
|
= OptionalTransformRange<DeclRange,
|
|
ToStoredPropertyOrMissingMemberPlaceholder>;
|
|
|
|
/// Return a collection of the stored member variables of this type, along
|
|
/// with placeholders for unimportable stored properties.
|
|
StoredPropertyOrMissingMemberPlaceholderRange
|
|
getStoredPropertiesAndMissingMemberPlaceholders() const {
|
|
return StoredPropertyOrMissingMemberPlaceholderRange(getMembers(),
|
|
ToStoredPropertyOrMissingMemberPlaceholder());
|
|
}
|
|
|
|
// 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->getAsDeclOrDeclExtensionContext())
|
|
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; }
|
|
};
|
|
|
|
/// \brief 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;
|
|
|
|
struct {
|
|
/// The raw type and a bit to indicate whether the
|
|
/// raw was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> RawType;
|
|
} LazySemanticInfo;
|
|
|
|
friend class EnumRawTypeRequest;
|
|
friend class TypeChecker;
|
|
|
|
public:
|
|
EnumDecl(SourceLoc EnumLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return EnumLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(EnumLoc, getBraces().End);
|
|
}
|
|
|
|
EnumElementDecl *getElement(Identifier Name) const;
|
|
|
|
public:
|
|
/// A range for iterating the elements of an enum.
|
|
using ElementRange = DowncastFilterRange<EnumElementDecl, DeclRange>;
|
|
|
|
/// 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());
|
|
}
|
|
|
|
/// If this is an enum with two cases, return the other case. Otherwise,
|
|
/// return nullptr.
|
|
EnumElementDecl *getOppositeBinaryDecl(EnumElementDecl *decl) const {
|
|
ElementRange range = getAllElements();
|
|
auto iter = range.begin();
|
|
if (iter == range.end())
|
|
return nullptr;
|
|
bool seenDecl = false;
|
|
EnumElementDecl *result = nullptr;
|
|
if (*iter == decl) {
|
|
seenDecl = true;
|
|
} else {
|
|
result = *iter;
|
|
}
|
|
|
|
++iter;
|
|
if (iter == range.end())
|
|
return nullptr;
|
|
if (seenDecl) {
|
|
assert(!result);
|
|
result = *iter;
|
|
} else {
|
|
if (decl != *iter)
|
|
return nullptr;
|
|
seenDecl = true;
|
|
}
|
|
++iter;
|
|
|
|
// If we reach this point, we saw the decl we were looking for and one other
|
|
// case. If we have any additional cases, then we do not have a binary enum.
|
|
if (iter != range.end())
|
|
return nullptr;
|
|
|
|
// This is always true since we have already returned earlier nullptr if we
|
|
// did not see the decl at all.
|
|
assert(seenDecl);
|
|
return result;
|
|
}
|
|
|
|
/// 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);
|
|
}
|
|
|
|
/// Retrieve the status of circularity checking for class inheritance.
|
|
CircularityCheck getCircularityCheck() const {
|
|
return static_cast<CircularityCheck>(Bits.EnumDecl.Circularity);
|
|
}
|
|
|
|
/// Record the current stage of circularity checking.
|
|
void setCircularityCheck(CircularityCheck circularity) {
|
|
Bits.EnumDecl.Circularity = static_cast<unsigned>(circularity);
|
|
}
|
|
|
|
// 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->getAsDeclOrDeclExtensionContext())
|
|
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) {
|
|
LazySemanticInfo.RawType.setPointerAndInt(rawType, true);
|
|
}
|
|
|
|
/// 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 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.
|
|
bool isExhaustive(const DeclContext *useDC) 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;
|
|
|
|
public:
|
|
StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> 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->getAsDeclOrDeclExtensionContext())
|
|
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;
|
|
}
|
|
};
|
|
|
|
/// The kind of artificial main to generate for a class.
|
|
enum class ArtificialMainKind : uint8_t {
|
|
NSApplicationMain,
|
|
UIApplicationMain,
|
|
};
|
|
|
|
enum class ObjCClassKind : uint8_t {
|
|
/// Neither the class nor any of its superclasses are @objc.
|
|
NonObjC,
|
|
/// One of the superclasses is @objc but another superclass or the
|
|
/// class itself has generic parameters, so while it cannot be
|
|
/// directly represented in Objective-C, it has implicitly @objc
|
|
/// members.
|
|
ObjCMembers,
|
|
/// The top-level ancestor of this class is not @objc, but the
|
|
/// class itself is.
|
|
ObjCWithSwiftRoot,
|
|
/// The class is bona-fide @objc.
|
|
ObjC,
|
|
};
|
|
|
|
/// 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 {
|
|
class ObjCMethodLookupTable;
|
|
|
|
SourceLoc ClassLoc;
|
|
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
|
|
|
|
/// Create the Objective-C member lookup table.
|
|
void createObjCMethodLookup();
|
|
|
|
struct {
|
|
/// The superclass type and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> Superclass;
|
|
} LazySemanticInfo;
|
|
|
|
friend class SuperclassTypeRequest;
|
|
friend class TypeChecker;
|
|
|
|
public:
|
|
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return ClassLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(ClassLoc, getBraces().End);
|
|
}
|
|
|
|
/// Determine whether this class has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclass(); }
|
|
|
|
/// 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;
|
|
|
|
/// Set the superclass of this class.
|
|
void setSuperclass(Type superclass);
|
|
|
|
/// Retrieve the status of circularity checking for class inheritance.
|
|
CircularityCheck getCircularityCheck() const {
|
|
return static_cast<CircularityCheck>(Bits.ClassDecl.Circularity);
|
|
}
|
|
|
|
/// Record the current stage of circularity checking.
|
|
void setCircularityCheck(CircularityCheck circularity) {
|
|
Bits.ClassDecl.Circularity = static_cast<unsigned>(circularity);
|
|
}
|
|
|
|
//// Whether this class requires all of its stored properties to
|
|
//// have initializers in the class definition.
|
|
bool requiresStoredPropertyInits() const {
|
|
return Bits.ClassDecl.RequiresStoredPropertyInits;
|
|
}
|
|
|
|
/// Set whether this class requires all of its stored properties to
|
|
/// have initializers in the class definition.
|
|
void setRequiresStoredPropertyInits(bool requiresInits) {
|
|
Bits.ClassDecl.RequiresStoredPropertyInits = requiresInits;
|
|
}
|
|
|
|
/// \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;
|
|
}
|
|
|
|
/// 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;
|
|
|
|
void setHasMissingDesignatedInitializers(bool newValue = true) {
|
|
Bits.ClassDecl.HasMissingDesignatedInitializers = newValue;
|
|
}
|
|
|
|
/// 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.HasMissingVTableEntries = 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;
|
|
|
|
/// True if the class has a destructor.
|
|
///
|
|
/// Fully type-checked classes always contain destructors, but during parsing
|
|
/// or type-checking, the implicit destructor may not have been synthesized
|
|
/// yet if one was not explicitly declared.
|
|
bool hasDestructor() const { return Bits.ClassDecl.HasDestructorDecl; }
|
|
|
|
/// Set the 'has destructor' flag.
|
|
void setHasDestructor() { Bits.ClassDecl.HasDestructorDecl = 1; }
|
|
|
|
/// Retrieve the destructor for this class.
|
|
DestructorDecl *getDestructor();
|
|
|
|
/// Synthesize implicit, trivial destructor, add it to this ClassDecl
|
|
/// and return it.
|
|
void addImplicitDestructor();
|
|
|
|
/// Determine whether this class inherits the convenience initializers
|
|
/// from its superclass.
|
|
///
|
|
/// \param resolver Used to resolve the signatures of initializers, which is
|
|
/// required for name lookup.
|
|
bool inheritsSuperclassInitializers(LazyResolver *resolver);
|
|
|
|
/// Marks that this class inherits convenience initializers from its
|
|
/// superclass.
|
|
///
|
|
/// This is computed as part of adding implicit initializers.
|
|
void setInheritsSuperclassInitializers() {
|
|
assert(addedImplicitInitializers());
|
|
Bits.ClassDecl.InheritsSuperclassInits = true;
|
|
}
|
|
|
|
/// Figure out if this class has any @objc ancestors, in which case it should
|
|
/// have implicitly @objc members. Note that a class with generic ancestry
|
|
/// might have implicitly @objc members, but will never itself be @objc.
|
|
ObjCClassKind checkObjCAncestry() const;
|
|
|
|
/// 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;
|
|
|
|
/// 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 class that does not have a
|
|
/// *ApplicationMain attribute.
|
|
ArtificialMainKind getArtificialMainKind() const;
|
|
|
|
using NominalTypeDecl::lookupDirect;
|
|
|
|
/// Look in this class 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).
|
|
MutableArrayRef<AbstractFunctionDecl *> lookupDirect(ObjCSelector selector,
|
|
bool isInstance);
|
|
|
|
/// Record the presence of an @objc method whose Objective-C name has been
|
|
/// finalized.
|
|
void recordObjCMethod(AbstractFunctionDecl *method);
|
|
|
|
// 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->getAsDeclOrDeclExtensionContext())
|
|
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 usesObjCGenericsModel() const {
|
|
return isObjC() && hasClangNode() && isGenericContext();
|
|
}
|
|
|
|
/// True if the class is known to be implemented in Swift.
|
|
bool hasKnownSwiftImplementation() const {
|
|
return !hasClangNode();
|
|
}
|
|
};
|
|
|
|
|
|
/// Describes whether a requirement refers to 'Self', for use in the
|
|
/// is-inheritable and is-available-existential checks.
|
|
struct SelfReferenceKind {
|
|
bool result;
|
|
bool parameter;
|
|
bool requirement;
|
|
bool other;
|
|
|
|
/// The type does not refer to 'Self' at all.
|
|
static SelfReferenceKind None() {
|
|
return SelfReferenceKind(false, false, false, false);
|
|
}
|
|
|
|
/// The type refers to 'Self', but only as the result type of a method.
|
|
static SelfReferenceKind Result() {
|
|
return SelfReferenceKind(true, false, false, false);
|
|
}
|
|
|
|
/// The type refers to 'Self', but only as the parameter type of a method.
|
|
static SelfReferenceKind Parameter() {
|
|
return SelfReferenceKind(false, true, false, false);
|
|
}
|
|
|
|
/// The type refers to 'Self' within a same-type requiement.
|
|
static SelfReferenceKind Requirement() {
|
|
return SelfReferenceKind(false, false, true, false);
|
|
}
|
|
|
|
/// The type refers to 'Self' in a position that is invariant.
|
|
static SelfReferenceKind Other() {
|
|
return SelfReferenceKind(false, false, false, true);
|
|
}
|
|
|
|
SelfReferenceKind flip() const {
|
|
return SelfReferenceKind(parameter, result, requirement, other);
|
|
}
|
|
|
|
SelfReferenceKind operator|=(SelfReferenceKind kind) {
|
|
result |= kind.result;
|
|
requirement |= kind.requirement;
|
|
parameter |= kind.parameter;
|
|
other |= kind.other;
|
|
return *this;
|
|
}
|
|
|
|
operator bool() const {
|
|
return result || parameter || requirement || other;
|
|
}
|
|
|
|
private:
|
|
SelfReferenceKind(bool result, bool parameter, bool requirement, bool other)
|
|
: result(result), parameter(parameter), requirement(requirement),
|
|
other(other) { }
|
|
};
|
|
|
|
/// ProtocolDecl - A declaration of a protocol, for example:
|
|
///
|
|
/// protocol Drawable {
|
|
/// func draw()
|
|
/// }
|
|
class ProtocolDecl final : public NominalTypeDecl {
|
|
SourceLoc ProtocolLoc;
|
|
|
|
/// The syntactic representation of the where clause in a protocol like
|
|
/// `protocol ... where ... { ... }`.
|
|
TrailingWhereClause *TrailingWhere;
|
|
|
|
llvm::DenseMap<ValueDecl *, Witness> DefaultWitnesses;
|
|
|
|
/// The generic signature representing exactly the new requirements introduced
|
|
/// by this protocol.
|
|
const Requirement *RequirementSignature = nullptr;
|
|
|
|
bool requiresClassSlow();
|
|
|
|
bool existentialConformsToSelfSlow();
|
|
|
|
bool existentialTypeSupportedSlow(LazyResolver *resolver);
|
|
|
|
struct {
|
|
/// The superclass type and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> Superclass;
|
|
} LazySemanticInfo;
|
|
|
|
friend class SuperclassTypeRequest;
|
|
friend class TypeChecker;
|
|
|
|
public:
|
|
ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc,
|
|
Identifier Name, MutableArrayRef<TypeLoc> Inherited,
|
|
TrailingWhereClause *TrailingWhere);
|
|
|
|
using Decl::getASTContext;
|
|
|
|
/// Retrieve the set of protocols inherited from this protocol.
|
|
llvm::TinyPtrVector<ProtocolDecl *> getInheritedProtocols() const;
|
|
|
|
/// Determine whether this protocol has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclass(); }
|
|
|
|
/// Retrieve the superclass of this protocol, or null if there is no superclass.
|
|
Type getSuperclass() const;
|
|
|
|
/// Retrieve the ClassDecl for the superclass of this protocol, or null if there
|
|
/// is no superclass.
|
|
ClassDecl *getSuperclassDecl() const;
|
|
|
|
/// Set the superclass of this protocol.
|
|
void setSuperclass(Type superclass);
|
|
|
|
/// 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).
|
|
llvm::TinyPtrVector<AssociatedTypeDecl *> getAssociatedTypeMembers() const;
|
|
|
|
/// Walk 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;
|
|
|
|
/// \brief Determine whether this protocol inherits from the given ("super")
|
|
/// protocol.
|
|
bool inheritsFrom(const ProtocolDecl *Super) const;
|
|
|
|
ProtocolType *getDeclaredType() const {
|
|
return reinterpret_cast<ProtocolType *>(
|
|
NominalTypeDecl::getDeclaredType().getPointer());
|
|
}
|
|
|
|
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 {
|
|
if (Bits.ProtocolDecl.RequiresClassValid)
|
|
return Bits.ProtocolDecl.RequiresClass;
|
|
|
|
return const_cast<ProtocolDecl *>(this)->requiresClassSlow();
|
|
}
|
|
|
|
/// Specify that this protocol is class-bounded, e.g., because it was
|
|
/// annotated with the 'class' keyword.
|
|
void setRequiresClass(bool requiresClass = true) {
|
|
Bits.ProtocolDecl.RequiresClassValid = true;
|
|
Bits.ProtocolDecl.RequiresClass = requiresClass;
|
|
}
|
|
|
|
/// 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 {
|
|
if (Bits.ProtocolDecl.ExistentialConformsToSelfValid)
|
|
return Bits.ProtocolDecl.ExistentialConformsToSelf;
|
|
|
|
return const_cast<ProtocolDecl *>(this)
|
|
->existentialConformsToSelfSlow();
|
|
}
|
|
|
|
/// Find direct Self references within the given requirement.
|
|
///
|
|
/// \param allowCovariantParameters If true, 'Self' is assumed to be
|
|
/// covariant anywhere; otherwise, only in the return type of the top-level
|
|
/// function type.
|
|
///
|
|
/// \param skipAssocTypes If true, associated types of 'Self' are ignored;
|
|
/// otherwise, they count as an 'other' usage of 'Self'.
|
|
SelfReferenceKind findProtocolSelfReferences(const ValueDecl *decl,
|
|
bool allowCovariantParameters,
|
|
bool skipAssocTypes) const;
|
|
|
|
/// Determine whether we are allowed to refer to an existential type
|
|
/// conforming to this protocol. This is only permitted if the type of
|
|
/// the member does not contain any associated types, and does not
|
|
/// contain 'Self' in 'parameter' or 'other' position.
|
|
bool isAvailableInExistential(const ValueDecl *decl) const;
|
|
|
|
/// Determine whether we are allowed to refer to an existential type
|
|
/// conforming to this protocol. This is only permitted if the types of
|
|
/// all the members do not contain any associated types, and do not
|
|
/// contain 'Self' in 'parameter' or 'other' position.
|
|
bool existentialTypeSupported(LazyResolver *resolver) const {
|
|
if (Bits.ProtocolDecl.ExistentialTypeSupportedValid)
|
|
return Bits.ProtocolDecl.ExistentialTypeSupported;
|
|
|
|
return const_cast<ProtocolDecl *>(this)
|
|
->existentialTypeSupportedSlow(resolver);
|
|
}
|
|
|
|
/// Explicitly set the existentialTypeSupported flag, without computing
|
|
/// it from members. Only called from deserialization, where the flag
|
|
/// was stored in the serialized record.
|
|
void setExistentialTypeSupported(bool supported) {
|
|
Bits.ProtocolDecl.ExistentialTypeSupported = supported;
|
|
Bits.ProtocolDecl.ExistentialTypeSupportedValid = true;
|
|
}
|
|
|
|
/// If this is known to be a compiler-known protocol, returns the kind.
|
|
/// Otherwise returns None.
|
|
///
|
|
/// Note that this is only valid after type-checking.
|
|
Optional<KnownProtocolKind> getKnownProtocolKind() const {
|
|
if (Bits.ProtocolDecl.KnownProtocol == 0)
|
|
return None;
|
|
return static_cast<KnownProtocolKind>(Bits.ProtocolDecl.KnownProtocol - 1);
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Records that this is a compiler-known protocol.
|
|
void setKnownProtocolKind(KnownProtocolKind kind) {
|
|
assert((!getKnownProtocolKind() || *getKnownProtocolKind() == kind) &&
|
|
"can't reset known protocol kind");
|
|
Bits.ProtocolDecl.KnownProtocol = static_cast<unsigned>(kind) + 1;
|
|
assert(getKnownProtocolKind() && *getKnownProtocolKind() == kind &&
|
|
"not enough bits");
|
|
}
|
|
|
|
/// Retrieve the status of circularity checking for protocol inheritance.
|
|
CircularityCheck getCircularityCheck() const {
|
|
return static_cast<CircularityCheck>(Bits.ProtocolDecl.Circularity);
|
|
}
|
|
|
|
/// Record the current stage of circularity checking.
|
|
void setCircularityCheck(CircularityCheck circularity) {
|
|
Bits.ProtocolDecl.Circularity = static_cast<unsigned>(circularity);
|
|
}
|
|
|
|
/// 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 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);
|
|
|
|
/// Retrieve the name to use for this protocol when interoperating
|
|
/// with the Objective-C runtime.
|
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
|
|
|
/// Create the implicit generic parameter list for a protocol or
|
|
/// extension thereof.
|
|
GenericParamList *createGenericParams(DeclContext *dc);
|
|
|
|
/// Create the generic parameters of this protocol if the haven't been
|
|
/// created yet.
|
|
void createGenericParamsIfMissing();
|
|
|
|
/// Retrieve the trailing where clause on this protocol, if it exists.
|
|
TrailingWhereClause *getTrailingWhereClause() const {
|
|
return TrailingWhere;
|
|
}
|
|
|
|
/// Retrieve the requirements that describe this protocol.
|
|
///
|
|
/// These are the requirements including any inherited protocols
|
|
/// and conformances for associated types that are introduced in this
|
|
/// protocol. Requirements implied via any other protocol (e.g., inherited
|
|
/// protocols of the inherited protocols) are not mentioned. The conformance
|
|
/// requirements listed here become entries in the witness table.
|
|
ArrayRef<Requirement> getRequirementSignature() const {
|
|
assert(isRequirementSignatureComputed() &&
|
|
"getting requirement signature before computing it");
|
|
return llvm::makeArrayRef(RequirementSignature,
|
|
Bits.ProtocolDecl.NumRequirementsInSignature);
|
|
}
|
|
|
|
/// Has the requirement signature been computed yet?
|
|
bool isRequirementSignatureComputed() const {
|
|
return RequirementSignature != nullptr;
|
|
}
|
|
|
|
void computeRequirementSignature();
|
|
|
|
void setRequirementSignature(ArrayRef<Requirement> requirements);
|
|
|
|
// 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->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
};
|
|
|
|
/// Information about a behavior instantiated by a storage declaration.
|
|
///
|
|
/// TODO: Accessors, composed behaviors
|
|
struct alignas(1 << 3) BehaviorRecord {
|
|
// The behavior name.
|
|
TypeRepr *ProtocolName;
|
|
// The parameter expression, if any.
|
|
Expr *Param;
|
|
|
|
Optional<NormalProtocolConformance *> Conformance = None;
|
|
// The 'value' property from the behavior protocol that provides the property
|
|
// implementation.
|
|
VarDecl *ValueDecl = nullptr;
|
|
|
|
// Storage declaration and initializer for use by definite initialization.
|
|
VarDecl *StorageDecl = nullptr;
|
|
ConcreteDeclRef InitStorageDecl = nullptr;
|
|
|
|
bool needsInitialization() const {
|
|
assert((bool)StorageDecl == (bool)InitStorageDecl
|
|
&& "DI state not consistent");
|
|
return StorageDecl != nullptr;
|
|
}
|
|
|
|
BehaviorRecord(TypeRepr *ProtocolName,
|
|
Expr *Param)
|
|
: ProtocolName(ProtocolName), Param(Param)
|
|
{}
|
|
|
|
SourceLoc getLoc() const;
|
|
};
|
|
|
|
/// AbstractStorageDecl - This is the common superclass for VarDecl and
|
|
/// SubscriptDecl, representing potentially settable memory locations.
|
|
class AbstractStorageDecl : public ValueDecl {
|
|
friend class SetterAccessLevelRequest;
|
|
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 implementation info for the accessors. If there's no
|
|
/// AccessorRecord for a storage decl, the decl is just stored.
|
|
StorageImplInfo ImplInfo;
|
|
|
|
/// 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, StorageImplInfo implInfo,
|
|
ArrayRef<AccessorDecl*> accessors,
|
|
AccessorIndex accessorsCapacity);
|
|
public:
|
|
static AccessorRecord *create(ASTContext &ctx, SourceRange braces,
|
|
StorageImplInfo implInfo,
|
|
ArrayRef<AccessorDecl*> accessors);
|
|
|
|
SourceRange getBracesRange() const { return Braces; }
|
|
|
|
const StorageImplInfo &getImplInfo() const { return ImplInfo; }
|
|
void overwriteImplInfo(StorageImplInfo newInfo) { ImplInfo = newInfo; }
|
|
|
|
inline AccessorDecl *getAccessor(AccessorKind kind) const;
|
|
|
|
ArrayRef<AccessorDecl *> getAllAccessors() const {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
void addOpaqueAccessor(AccessorDecl *accessor);
|
|
|
|
private:
|
|
MutableArrayRef<AccessorDecl *> getAccessorsBuffer() {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
bool registerAccessor(AccessorDecl *accessor, AccessorIndex index);
|
|
};
|
|
|
|
llvm::PointerIntPair<AccessorRecord*, 3, OptionalEnum<AccessLevel>> Accessors;
|
|
llvm::PointerIntPair<BehaviorRecord*, 3, OptionalEnum<AccessLevel>>
|
|
BehaviorInfo;
|
|
|
|
void configureAccessor(AccessorDecl *accessor);
|
|
void setFieldsFromImplInfo(StorageImplInfo implInfo) {
|
|
Bits.AbstractStorageDecl.HasStorage = implInfo.hasStorage();
|
|
Bits.AbstractStorageDecl.SupportsMutation = implInfo.supportsMutation();
|
|
}
|
|
|
|
protected:
|
|
AbstractStorageDecl(DeclKind Kind, DeclContext *DC, DeclName Name,
|
|
SourceLoc NameLoc, bool supportsMutation)
|
|
: ValueDecl(Kind, DC, Name, NameLoc) {
|
|
Bits.AbstractStorageDecl.HasStorage = true;
|
|
Bits.AbstractStorageDecl.SupportsMutation = supportsMutation;
|
|
Bits.AbstractStorageDecl.IsGetterMutating = false;
|
|
Bits.AbstractStorageDecl.IsSetterMutating = true;
|
|
}
|
|
|
|
void setSupportsMutationIfStillStored(bool supportsMutation) {
|
|
if (auto ptr = Accessors.getPointer()) {
|
|
auto impl = ptr->getImplInfo();
|
|
if (!impl.isSimpleStored()) return;
|
|
impl = StorageImplInfo::getSimpleStored(supportsMutation);
|
|
ptr->overwriteImplInfo(impl);
|
|
}
|
|
Bits.AbstractStorageDecl.SupportsMutation = supportsMutation;
|
|
}
|
|
|
|
public:
|
|
|
|
/// \brief Should this declaration be treated as if annotated with transparent
|
|
/// attribute.
|
|
bool isTransparent() const;
|
|
|
|
/// \brief Determine whether this storage is a static member, if it
|
|
/// is a member. Currently only variables can be static.
|
|
inline bool isStatic() const; // defined in this header
|
|
|
|
/// \brief Return the interface type of the stored value.
|
|
Type getValueInterfaceType() const;
|
|
|
|
/// \brief Determine how this storage is implemented.
|
|
StorageImplInfo getImplInfo() const {
|
|
if (auto ptr = Accessors.getPointer())
|
|
return ptr->getImplInfo();
|
|
return StorageImplInfo::getSimpleStored(supportsMutation());
|
|
}
|
|
|
|
ReadImplKind getReadImpl() const {
|
|
return getImplInfo().getReadImpl();
|
|
}
|
|
WriteImplKind getWriteImpl() const {
|
|
return getImplInfo().getWriteImpl();
|
|
}
|
|
ReadWriteImplKind getReadWriteImpl() const {
|
|
return getImplInfo().getReadWriteImpl();
|
|
}
|
|
|
|
/// Overwrite the registered implementation-info. This should be
|
|
/// used carefully.
|
|
void overwriteImplInfo(StorageImplInfo implInfo);
|
|
|
|
/// \brief Return true if this is a VarDecl that has storage associated with
|
|
/// it.
|
|
bool hasStorage() const {
|
|
return Bits.AbstractStorageDecl.HasStorage;
|
|
}
|
|
|
|
/// \brief 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).
|
|
bool supportsMutation() const {
|
|
return Bits.AbstractStorageDecl.SupportsMutation;
|
|
}
|
|
|
|
/// Are there any accessors for this declaration, including implicit ones?
|
|
bool hasAnyAccessors() const {
|
|
return !getAllAccessors().empty();
|
|
}
|
|
|
|
/// \brief Return true if reading this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isGetterMutating() const {
|
|
return Bits.AbstractStorageDecl.IsGetterMutating;
|
|
}
|
|
void setIsGetterMutating(bool isMutating) {
|
|
Bits.AbstractStorageDecl.IsGetterMutating = isMutating;
|
|
}
|
|
|
|
/// \brief Return true if modifying this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isSetterMutating() const {
|
|
return Bits.AbstractStorageDecl.IsSetterMutating;
|
|
}
|
|
void setIsSetterMutating(bool isMutating) {
|
|
Bits.AbstractStorageDecl.IsSetterMutating = isMutating;
|
|
}
|
|
|
|
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 setAccessors(StorageImplInfo storageImpl,
|
|
SourceLoc lbraceLoc, ArrayRef<AccessorDecl*> accessors,
|
|
SourceLoc rbraceLoc);
|
|
|
|
/// \brief Add a setter to an existing Computed var.
|
|
///
|
|
/// This should only be used by the ClangImporter.
|
|
void setComputedSetter(AccessorDecl *Set);
|
|
|
|
/// \brief Add a behavior to a property.
|
|
void addBehavior(TypeRepr *Type, Expr *Param);
|
|
|
|
/// \brief Add a synthesized getter.
|
|
void setSynthesizedGetter(AccessorDecl *getter);
|
|
|
|
/// \brief Add a synthesized setter.
|
|
void setSynthesizedSetter(AccessorDecl *setter);
|
|
|
|
/// \brief Add a synthesized materializeForSet accessor.
|
|
void setSynthesizedMaterializeForSet(AccessorDecl *materializeForSet);
|
|
|
|
SourceRange getBracesRange() const {
|
|
if (auto info = Accessors.getPointer())
|
|
return info->getBracesRange();
|
|
return SourceRange();
|
|
}
|
|
|
|
/// \brief Retrieve the getter used to access the value of this variable.
|
|
AccessorDecl *getGetter() const {
|
|
return getAccessor(AccessorKind::Get);
|
|
}
|
|
|
|
/// \brief Retrieve the setter used to mutate the value of this variable.
|
|
AccessorDecl *getSetter() const {
|
|
return getAccessor(AccessorKind::Set);
|
|
}
|
|
|
|
AccessLevel getSetterFormalAccess() const;
|
|
|
|
void setSetterAccess(AccessLevel accessLevel) {
|
|
assert(!Accessors.getInt().hasValue());
|
|
overwriteSetterAccess(accessLevel);
|
|
}
|
|
|
|
void overwriteSetterAccess(AccessLevel accessLevel);
|
|
|
|
/// \brief Retrieve the materializeForSet function, if this
|
|
/// declaration has one.
|
|
AccessorDecl *getMaterializeForSetFunc() const {
|
|
return getAccessor(AccessorKind::MaterializeForSet);
|
|
}
|
|
|
|
/// \brief Return the decl for the immutable addressor if it exists.
|
|
AccessorDecl *getAddressor() const {
|
|
return getAccessor(AccessorKind::Address);
|
|
}
|
|
|
|
/// \brief Return the decl for the mutable accessor if it exists.
|
|
AccessorDecl *getMutableAddressor() const {
|
|
return getAccessor(AccessorKind::MutableAddress);
|
|
}
|
|
|
|
/// \brief Return the appropriate addressor for the given access kind.
|
|
AccessorDecl *getAddressorForAccess(AccessKind accessKind) const {
|
|
if (accessKind == AccessKind::Read)
|
|
return getAddressor();
|
|
return getMutableAddressor();
|
|
}
|
|
|
|
/// \brief Return the decl for the 'read' coroutine accessor if it exists.
|
|
AccessorDecl *getReadCoroutine() const {
|
|
return getAccessor(AccessorKind::Read);
|
|
}
|
|
|
|
/// \brief Return the decl for the 'modify' coroutine accessor if it exists.
|
|
AccessorDecl *getModifyCoroutine() const {
|
|
return getAccessor(AccessorKind::Modify);
|
|
}
|
|
|
|
/// \brief Return the decl for the willSet specifier if it exists, this is
|
|
/// only valid on a declaration with Observing storage.
|
|
AccessorDecl *getWillSetFunc() const {
|
|
return getAccessor(AccessorKind::WillSet);
|
|
}
|
|
|
|
/// \brief Return the decl for the didSet specifier if it exists, this is
|
|
/// only valid on a declaration with Observing storage.
|
|
AccessorDecl *getDidSetFunc() const {
|
|
return getAccessor(AccessorKind::DidSet);
|
|
}
|
|
|
|
/// 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,
|
|
DeclContext *accessFromDC = nullptr) const;
|
|
|
|
/// \brief Should this declaration behave as if it must be accessed
|
|
/// resiliently, even when we're building a non-resilient module?
|
|
///
|
|
/// This is used for diagnostics, because we do not want a behavior
|
|
/// change between builds with resilience enabled and disabled.
|
|
bool isFormallyResilient() const;
|
|
|
|
/// \brief Do we need to use resilient access patterns outside of this
|
|
/// property's resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// \brief Do we need to use resilient access patterns when accessing this
|
|
/// property from the given module?
|
|
bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// Returns the interface type of elements of storage represented by this
|
|
/// declaration.
|
|
///
|
|
/// For variables, this is the type of the variable itself.
|
|
/// For subscripts, this is the type of the subscript element.
|
|
Type getStorageInterfaceType() const;
|
|
|
|
/// Does the storage use a behavior?
|
|
bool hasBehavior() const {
|
|
return BehaviorInfo.getPointer() != nullptr;
|
|
}
|
|
|
|
/// Does the storage use a behavior, and require definite initialization
|
|
/// analysis.
|
|
bool hasBehaviorNeedingInitialization() const {
|
|
if (auto behavior = getBehavior()) {
|
|
return behavior->needsInitialization();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// Get the behavior info.
|
|
const BehaviorRecord *getBehavior() const {
|
|
return BehaviorInfo.getPointer();
|
|
}
|
|
BehaviorRecord *getMutableBehavior() {
|
|
return BehaviorInfo.getPointer();
|
|
}
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_AbstractStorageDecl &&
|
|
D->getKind() <= DeclKind::Last_AbstractStorageDecl;
|
|
}
|
|
};
|
|
|
|
/// VarDecl - 'var' and 'let' declarations.
|
|
class VarDecl : public AbstractStorageDecl {
|
|
public:
|
|
enum class Specifier : uint8_t {
|
|
// For Var Decls
|
|
|
|
Let = 0,
|
|
Var = 1,
|
|
|
|
// For Param Decls
|
|
|
|
Default = Let,
|
|
InOut = 2,
|
|
Shared = 3,
|
|
Owned = 4,
|
|
};
|
|
|
|
protected:
|
|
llvm::PointerUnion<PatternBindingDecl*, Stmt*> ParentPattern;
|
|
|
|
VarDecl(DeclKind Kind, bool IsStatic, Specifier Sp, bool IsCaptureList,
|
|
SourceLoc NameLoc, Identifier Name, Type Ty, DeclContext *DC)
|
|
: AbstractStorageDecl(Kind, DC, Name, NameLoc, !isImmutableSpecifier(Sp))
|
|
{
|
|
Bits.VarDecl.IsStatic = IsStatic;
|
|
Bits.VarDecl.Specifier = static_cast<unsigned>(Sp);
|
|
Bits.VarDecl.IsCaptureList = IsCaptureList;
|
|
Bits.VarDecl.IsDebuggerVar = false;
|
|
Bits.VarDecl.IsREPLVar = false;
|
|
Bits.VarDecl.HasNonPatternBindingInit = false;
|
|
setType(Ty);
|
|
}
|
|
|
|
/// This is the type specified, including location information.
|
|
TypeLoc typeLoc;
|
|
|
|
Type typeInContext;
|
|
|
|
public:
|
|
VarDecl(bool IsStatic, Specifier Sp, bool IsCaptureList, SourceLoc NameLoc,
|
|
Identifier Name, Type Ty, DeclContext *DC)
|
|
: VarDecl(DeclKind::Var, IsStatic, Sp, IsCaptureList, NameLoc, Name, Ty,
|
|
DC) {}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getFullName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseName().getIdentifier().str() : "_";
|
|
}
|
|
|
|
TypeLoc &getTypeLoc() { return typeLoc; }
|
|
TypeLoc getTypeLoc() const { return typeLoc; }
|
|
|
|
bool hasType() const {
|
|
// We have a type if either the type has been computed already or if
|
|
// this is a deserialized declaration with an interface type.
|
|
return !typeInContext.isNull();
|
|
}
|
|
|
|
/// Get the type of the variable within its context. If the context is generic,
|
|
/// this will use archetypes.
|
|
Type getType() const;
|
|
|
|
/// Set the type of the variable within its context.
|
|
void setType(Type t);
|
|
|
|
void markInvalid();
|
|
|
|
/// 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;
|
|
|
|
/// \brief Returns whether the var is settable in the specified context: this
|
|
/// is either because it is a stored var, because it has a custom setter, or
|
|
/// is a let member in an initializer.
|
|
///
|
|
/// Pass a null context and null base to check if it's always settable.
|
|
bool isSettable(const DeclContext *UseDC,
|
|
const DeclRefExpr *base = nullptr) 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 {
|
|
return ParentPattern.dyn_cast<PatternBindingDecl *>();
|
|
}
|
|
void setParentPatternBinding(PatternBindingDecl *PBD) {
|
|
ParentPattern = 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;
|
|
|
|
/// Return the statement that owns the pattern associated with this VarDecl,
|
|
/// if one exists.
|
|
Stmt *getParentPatternStmt() const {
|
|
return ParentPattern.dyn_cast<Stmt*>();
|
|
}
|
|
void setParentPatternStmt(Stmt *S) {
|
|
ParentPattern = S;
|
|
}
|
|
|
|
/// 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())
|
|
return PBD->getPatternEntryForVarDecl(this).getInit();
|
|
return nullptr;
|
|
}
|
|
|
|
VarDecl *getOverriddenDecl() const {
|
|
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Determine whether this declaration is an anonymous closure parameter.
|
|
bool isAnonClosureParam() const;
|
|
|
|
/// Return the raw specifier value for this property or parameter.
|
|
Specifier getSpecifier() const {
|
|
return static_cast<Specifier>(Bits.VarDecl.Specifier);
|
|
}
|
|
void setSpecifier(Specifier Spec);
|
|
|
|
/// Is the type of this parameter 'inout'?
|
|
///
|
|
/// FIXME(Remove InOut): This is only valid on ParamDecls but multiple parts
|
|
/// of the compiler check ParamDecls and VarDecls along the same paths.
|
|
bool isInOut() const {
|
|
// FIXME: Re-enable this assertion and fix callers.
|
|
// assert((getKind() == DeclKind::Param) && "querying 'inout' on var decl?");
|
|
return getSpecifier() == Specifier::InOut;
|
|
}
|
|
|
|
|
|
/// Is this a type ('static') variable?
|
|
bool isStatic() const { return Bits.VarDecl.IsStatic; }
|
|
void setStatic(bool IsStatic) { Bits.VarDecl.IsStatic = IsStatic; }
|
|
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
|
|
bool isImmutable() const {
|
|
return isImmutableSpecifier(getSpecifier());
|
|
}
|
|
static bool isImmutableSpecifier(Specifier sp) {
|
|
switch (sp) {
|
|
case Specifier::Let:
|
|
case Specifier::Shared:
|
|
case Specifier::Owned:
|
|
return true;
|
|
case Specifier::Var:
|
|
case Specifier::InOut:
|
|
return false;
|
|
}
|
|
}
|
|
/// Is this an immutable 'let' property?
|
|
bool isLet() const { return getSpecifier() == Specifier::Let; }
|
|
/// Is this an immutable 'shared' property?
|
|
bool isShared() const { return getSpecifier() == Specifier::Shared; }
|
|
/// Is this an immutable 'owned' property?
|
|
bool isOwned() const { return getSpecifier() == Specifier::Owned; }
|
|
|
|
ValueOwnership getValueOwnership() const {
|
|
switch (getSpecifier()) {
|
|
case Specifier::Let:
|
|
return ValueOwnership::Default;
|
|
case Specifier::Var:
|
|
return ValueOwnership::Default;
|
|
case Specifier::InOut:
|
|
return ValueOwnership::InOut;
|
|
case Specifier::Shared:
|
|
return ValueOwnership::Shared;
|
|
case Specifier::Owned:
|
|
return ValueOwnership::Owned;
|
|
}
|
|
}
|
|
|
|
/// Is this an element in a capture list?
|
|
bool isCaptureList() const { return Bits.VarDecl.IsCaptureList; }
|
|
|
|
/// Return true if this vardecl has an initial value bound to it in a way
|
|
/// that isn't represented in the AST with an initializer in the pattern
|
|
/// binding. This happens in cases like "for i in ...", switch cases, etc.
|
|
bool hasNonPatternBindingInit() const {
|
|
return Bits.VarDecl.HasNonPatternBindingInit;
|
|
}
|
|
void setHasNonPatternBindingInit(bool V = true) {
|
|
Bits.VarDecl.HasNonPatternBindingInit = V;
|
|
}
|
|
|
|
/// Is this a special debugger variable?
|
|
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
|
void setDebuggerVar(bool IsDebuggerVar) {
|
|
Bits.VarDecl.IsDebuggerVar = IsDebuggerVar;
|
|
}
|
|
|
|
/// Is this a special debugger REPL variable?
|
|
/// FIXME: Remove this once LLDB has proper support for resilience.
|
|
bool isREPLVar() const { return Bits.VarDecl.IsREPLVar; }
|
|
void setREPLVar(bool IsREPLVar) {
|
|
Bits.VarDecl.IsREPLVar = IsREPLVar;
|
|
}
|
|
|
|
/// 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;
|
|
|
|
// 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 {
|
|
Identifier ArgumentName;
|
|
SourceLoc ArgumentNameLoc;
|
|
SourceLoc SpecifierLoc;
|
|
|
|
struct StoredDefaultArgument {
|
|
Expr *DefaultArg = nullptr;
|
|
Initializer *InitContext = nullptr;
|
|
};
|
|
|
|
/// The default value, if any, along with whether this is varargs.
|
|
llvm::PointerIntPair<StoredDefaultArgument *, 1> DefaultValueAndIsVariadic;
|
|
|
|
public:
|
|
ParamDecl(VarDecl::Specifier specifier,
|
|
SourceLoc specifierLoc, SourceLoc argumentNameLoc,
|
|
Identifier argumentName, SourceLoc parameterNameLoc,
|
|
Identifier parameterName, Type ty, DeclContext *dc);
|
|
|
|
/// Clone constructor, allocates a new ParamDecl identical to the first.
|
|
/// Intentionally not defined as a typical copy constructor to avoid
|
|
/// accidental copies.
|
|
ParamDecl(ParamDecl *PD, bool withTypes);
|
|
|
|
/// Retrieve the argument (API) name for this function parameter.
|
|
Identifier getArgumentName() const { return ArgumentName; }
|
|
|
|
/// 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; }
|
|
|
|
/// Retrieve the parameter type flags corresponding to the declaration of
|
|
/// this parameter's argument type.
|
|
ParameterTypeFlags getParameterFlags() const;
|
|
|
|
SourceLoc getSpecifierLoc() const { return SpecifierLoc; }
|
|
|
|
bool isTypeLocImplicit() const { return Bits.ParamDecl.IsTypeLocImplicit; }
|
|
void setIsTypeLocImplicit(bool val) { Bits.ParamDecl.IsTypeLocImplicit = val; }
|
|
|
|
DefaultArgumentKind getDefaultArgumentKind() const {
|
|
return static_cast<DefaultArgumentKind>(Bits.ParamDecl.defaultArgumentKind);
|
|
}
|
|
bool isDefaultArgument() const {
|
|
return getDefaultArgumentKind() != DefaultArgumentKind::None;
|
|
}
|
|
void setDefaultArgumentKind(DefaultArgumentKind K) {
|
|
Bits.ParamDecl.defaultArgumentKind = static_cast<unsigned>(K);
|
|
}
|
|
|
|
Expr *getDefaultValue() const {
|
|
if (auto stored = DefaultValueAndIsVariadic.getPointer())
|
|
return stored->DefaultArg;
|
|
return nullptr;
|
|
}
|
|
|
|
void setDefaultValue(Expr *E);
|
|
|
|
Initializer *getDefaultArgumentInitContext() const {
|
|
if (auto stored = DefaultValueAndIsVariadic.getPointer())
|
|
return stored->InitContext;
|
|
return nullptr;
|
|
}
|
|
|
|
void setDefaultArgumentInitContext(Initializer *initContext);
|
|
|
|
/// Whether or not this parameter is varargs.
|
|
bool isVariadic() const { return DefaultValueAndIsVariadic.getInt(); }
|
|
void setVariadic(bool value = true) {DefaultValueAndIsVariadic.setInt(value);}
|
|
|
|
/// 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());
|
|
}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Create an implicit 'self' decl for a method in the specified decl context.
|
|
/// If 'static' is true, then this is self for a static method in the type.
|
|
///
|
|
/// Note that this decl is created, but it is returned with an incorrect
|
|
/// DeclContext that needs to be set correctly. This is automatically handled
|
|
/// when a function is created with this as part of its argument list.
|
|
/// For a generic context, this also gives the parameter an unbound generic
|
|
/// type with the expectation that type-checking will fill in the context
|
|
/// generic parameters.
|
|
static ParamDecl *createUnboundSelf(SourceLoc loc, DeclContext *DC);
|
|
|
|
/// Create an implicit 'self' decl for a method in the specified decl context.
|
|
/// If 'static' is true, then this is self for a static method in the type.
|
|
///
|
|
/// Note that this decl is created, but it is returned with an incorrect
|
|
/// DeclContext that needs to be set correctly. This is automatically handled
|
|
/// when a function is created with this as part of its argument list.
|
|
static ParamDecl *createSelf(SourceLoc loc, DeclContext *DC,
|
|
bool isStatic = false,
|
|
bool isInOut = false);
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Param;
|
|
}
|
|
};
|
|
|
|
/// Describes the kind of subscripting used in Objective-C.
|
|
enum class ObjCSubscriptKind {
|
|
/// Not an Objective-C subscripting kind.
|
|
None,
|
|
/// 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
|
|
};
|
|
|
|
/// \brief 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 {
|
|
SourceLoc ArrowLoc;
|
|
ParameterList *Indices;
|
|
TypeLoc ElementTy;
|
|
|
|
public:
|
|
SubscriptDecl(DeclName Name, SourceLoc SubscriptLoc, ParameterList *Indices,
|
|
SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::SubscriptDecl, Parent),
|
|
AbstractStorageDecl(DeclKind::Subscript, Parent, Name, SubscriptLoc,
|
|
/*supports mutation (will be overwritten)*/ true),
|
|
ArrowLoc(ArrowLoc), Indices(nullptr), ElementTy(ElementTy) {
|
|
setIndices(Indices);
|
|
setGenericParams(GenericParams);
|
|
}
|
|
|
|
SourceLoc getSubscriptLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getSubscriptLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
/// \brief Retrieve the indices for this subscript operation.
|
|
ParameterList *getIndices() { return Indices; }
|
|
const ParameterList *getIndices() const { return Indices; }
|
|
void setIndices(ParameterList *p);
|
|
|
|
/// Retrieve the interface type of the indices.
|
|
Type getIndicesInterfaceType() const;
|
|
|
|
/// \brief Retrieve the type of the element referenced by a subscript
|
|
/// operation.
|
|
Type getElementInterfaceType() const;
|
|
TypeLoc &getElementTypeLoc() { return ElementTy; }
|
|
const TypeLoc &getElementTypeLoc() const { return ElementTy; }
|
|
|
|
/// Compute the interface type of this subscript from the parameter and
|
|
/// element types.
|
|
void computeType();
|
|
|
|
/// \brief Returns whether the result of the subscript operation can be set.
|
|
bool isSettable() const;
|
|
|
|
/// 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->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
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;
|
|
}
|
|
};
|
|
|
|
/// \brief Base class for function-like declarations.
|
|
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
|
|
public:
|
|
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 is not available, although it was written in the source.
|
|
Skipped,
|
|
|
|
/// Function body will be synthesized on demand.
|
|
Synthesize,
|
|
|
|
/// Function body is present and type-checked.
|
|
TypeChecked,
|
|
|
|
/// This is a memberwise initializer that will be synthesized by SILGen.
|
|
MemberwiseInitializer
|
|
|
|
// This enum currently needs to fit in a 3-bit bitfield.
|
|
};
|
|
|
|
BodyKind getBodyKind() const {
|
|
return BodyKind(Bits.AbstractFunctionDecl.BodyKind);
|
|
}
|
|
|
|
using BodySynthesizer = void (*)(AbstractFunctionDecl *);
|
|
|
|
private:
|
|
ParameterList *Params;
|
|
|
|
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.
|
|
BraceStmt *Body;
|
|
|
|
/// 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 or
|
|
/// BodyKind::Skipped.
|
|
SourceRange BodyRange;
|
|
};
|
|
|
|
CaptureInfo Captures;
|
|
|
|
/// Location of the 'throws' token.
|
|
SourceLoc ThrowsLoc;
|
|
|
|
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
|
|
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent),
|
|
ValueDecl(Kind, Parent, Name, NameLoc),
|
|
Body(nullptr), ThrowsLoc(ThrowsLoc) {
|
|
setBodyKind(BodyKind::None);
|
|
setGenericParams(GenericParams);
|
|
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
|
|
Bits.AbstractFunctionDecl.Overridden = false;
|
|
Bits.AbstractFunctionDecl.Throws = Throws;
|
|
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = false;
|
|
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = false;
|
|
Bits.AbstractFunctionDecl.DefaultArgumentResilienceExpansion =
|
|
unsigned(ResilienceExpansion::Maximal);
|
|
Bits.AbstractFunctionDecl.Synthesized = false;
|
|
}
|
|
|
|
void setBodyKind(BodyKind K) {
|
|
Bits.AbstractFunctionDecl.BodyKind = unsigned(K);
|
|
}
|
|
|
|
public:
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getFullName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseName().getIdentifier().str() : "_";
|
|
}
|
|
|
|
/// \brief 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 'throws' keyword, if present.
|
|
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
|
|
|
|
/// Returns true if the function body throws.
|
|
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }
|
|
|
|
// 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 {
|
|
return getBodyKind() != BodyKind::None;
|
|
}
|
|
|
|
/// 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 {
|
|
if (canSynthesize && getBodyKind() == BodyKind::Synthesize) {
|
|
const_cast<AbstractFunctionDecl *>(this)->setBodyKind(BodyKind::None);
|
|
(*Synthesizer)(const_cast<AbstractFunctionDecl *>(this));
|
|
}
|
|
if (getBodyKind() == BodyKind::Parsed ||
|
|
getBodyKind() == BodyKind::TypeChecked) {
|
|
return Body;
|
|
}
|
|
return nullptr;
|
|
}
|
|
void setBody(BraceStmt *S, BodyKind NewBodyKind = BodyKind::Parsed) {
|
|
assert(getBodyKind() != BodyKind::Skipped &&
|
|
"cannot set a body if it was skipped");
|
|
|
|
Body = S;
|
|
setBodyKind(NewBodyKind);
|
|
}
|
|
|
|
/// \brief Note that the body was skipped for this function. Function body
|
|
/// cannot be attached after this call.
|
|
void setBodySkipped(SourceRange bodyRange) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
BodyRange = bodyRange;
|
|
setBodyKind(BodyKind::Skipped);
|
|
}
|
|
|
|
/// \brief Note that parsing for the body was delayed.
|
|
void setBodyDelayed(SourceRange bodyRange) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
BodyRange = bodyRange;
|
|
setBodyKind(BodyKind::Unparsed);
|
|
}
|
|
|
|
/// Note that parsing for the body was delayed.
|
|
void setBodySynthesizer(BodySynthesizer synthesizer) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
Synthesizer = synthesizer;
|
|
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::MemberwiseInitializer);
|
|
}
|
|
|
|
/// If a body has been loaded, flag that it's been type-checked.
|
|
/// This is kindof a hacky operation, but it avoids some unnecessary
|
|
/// duplication of work.
|
|
void setBodyTypeCheckedIfPresent() {
|
|
if (getBodyKind() == BodyKind::Parsed)
|
|
setBodyKind(BodyKind::TypeChecked);
|
|
}
|
|
|
|
bool isBodyTypeChecked() const {
|
|
return getBodyKind() == BodyKind::TypeChecked;
|
|
}
|
|
|
|
bool isMemberwiseInitializer() const {
|
|
return getBodyKind() == BodyKind::MemberwiseInitializer;
|
|
}
|
|
|
|
void setNeedsNewVTableEntry(bool value) {
|
|
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = true;
|
|
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = value;
|
|
}
|
|
|
|
bool needsNewVTableEntry() const {
|
|
if (!Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry)
|
|
const_cast<AbstractFunctionDecl *>(this)->computeNeedsNewVTableEntry();
|
|
return Bits.AbstractFunctionDecl.NeedsNewVTableEntry;
|
|
}
|
|
|
|
bool isSynthesized() const {
|
|
return Bits.AbstractFunctionDecl.Synthesized;
|
|
}
|
|
|
|
void setSynthesized(bool value = true) {
|
|
Bits.AbstractFunctionDecl.Synthesized = value;
|
|
}
|
|
|
|
private:
|
|
void computeNeedsNewVTableEntry();
|
|
|
|
public:
|
|
/// Compute the interface type of this function declaration from the
|
|
/// parameter types.
|
|
void computeType(AnyFunctionType::ExtInfo Info = FunctionType::ExtInfo());
|
|
|
|
/// Retrieve the source range of the function body.
|
|
SourceRange getBodySourceRange() const;
|
|
|
|
/// Retrieve the source range of the function declaration name + patterns.
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
CaptureInfo &getCaptureInfo() { return Captures; }
|
|
const CaptureInfo &getCaptureInfo() const { return Captures; }
|
|
|
|
/// Retrieve the Objective-C selector that names this method.
|
|
ObjCSelector getObjCSelector(DeclName preferredName = DeclName()) 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(ParamDecl *SelfDecl,
|
|
ParameterList *Params);
|
|
|
|
bool hasImplicitSelfDecl() const {
|
|
return Bits.AbstractFunctionDecl.HasImplicitSelfDecl;
|
|
}
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Retrieve the implicit 'self' parameter for methods, or nullptr for free
|
|
/// functions.
|
|
const ParamDecl *getImplicitSelfDecl() const {
|
|
return const_cast<AbstractFunctionDecl*>(this)->getImplicitSelfDecl();
|
|
}
|
|
ParamDecl *getImplicitSelfDecl() {
|
|
auto **selfDecl = getImplicitSelfDeclStorage();
|
|
return (selfDecl == nullptr ? nullptr : *selfDecl);
|
|
}
|
|
|
|
/// Retrieve the declaration that this method overrides, if any.
|
|
AbstractFunctionDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AbstractFunctionDecl>(ValueDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Returns true if a function declaration overrides a given
|
|
/// method from its direct or indirect superclass.
|
|
bool isOverridingDecl(const AbstractFunctionDecl *method) const;
|
|
|
|
/// 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; }
|
|
|
|
/// The ResilienceExpansion for default arguments.
|
|
///
|
|
/// In Swift 4 mode, default argument expressions are serialized, and must
|
|
/// obey the restrictions imposed upon inlinable function bodies.
|
|
ResilienceExpansion getDefaultArgumentResilienceExpansion() const {
|
|
return ResilienceExpansion(
|
|
Bits.AbstractFunctionDecl.DefaultArgumentResilienceExpansion);
|
|
}
|
|
|
|
/// Set the ResilienceExpansion for default arguments.
|
|
void setDefaultArgumentResilienceExpansion(ResilienceExpansion expansion) {
|
|
Bits.AbstractFunctionDecl.DefaultArgumentResilienceExpansion =
|
|
unsigned(expansion);
|
|
}
|
|
|
|
/// 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'.
|
|
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.
|
|
Optional<int> getForeignFunctionAsMethodSelfParameterIndex() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_AbstractFunctionDecl &&
|
|
D->getKind() <= DeclKind::Last_AbstractFunctionDecl;
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the declaration is forced to be statically dispatched.
|
|
bool hasForcedStaticDispatch() const;
|
|
|
|
/// Get the interface type of this decl and remove the Self context.
|
|
Type getMethodInterfaceType() const;
|
|
|
|
using DeclContext::operator new;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
class OperatorDecl;
|
|
|
|
/// Note: These align with '%select's in diagnostics.
|
|
enum class SelfAccessKind : uint8_t {
|
|
NonMutating = 0,
|
|
Mutating = 1,
|
|
__Consuming = 2,
|
|
};
|
|
|
|
/// FuncDecl - 'func' declaration.
|
|
class FuncDecl : public AbstractFunctionDecl {
|
|
friend class AbstractFunctionDecl;
|
|
|
|
SourceLoc StaticLoc; // Location of the 'static' token or invalid.
|
|
SourceLoc FuncLoc; // Location of the 'func' token.
|
|
|
|
TypeLoc FnRetType;
|
|
|
|
/// \brief If this FuncDecl is an accessor for a property, this indicates
|
|
/// which property and what kind of accessor.
|
|
BehaviorRecord *BehaviorParamDecl = nullptr;
|
|
OperatorDecl *Operator = nullptr;
|
|
|
|
protected:
|
|
FuncDecl(DeclKind Kind,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: AbstractFunctionDecl(Kind, Parent,
|
|
Name, NameLoc,
|
|
Throws, ThrowsLoc,
|
|
HasImplicitSelfDecl, GenericParams),
|
|
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
|
|
assert(!Name.getBaseName().isSpecial());
|
|
|
|
Bits.FuncDecl.IsStatic =
|
|
StaticLoc.isValid() || StaticSpelling != StaticSpellingKind::None;
|
|
Bits.FuncDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
|
|
Bits.FuncDecl.HasDynamicSelf = false;
|
|
Bits.FuncDecl.ForcedStaticDispatch = false;
|
|
Bits.FuncDecl.SelfAccess = static_cast<unsigned>(SelfAccessKind::NonMutating);
|
|
}
|
|
|
|
private:
|
|
static FuncDecl *createImpl(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
bool HasImplicitSelfDecl,
|
|
DeclContext *Parent,
|
|
ClangNode ClangN);
|
|
|
|
public:
|
|
/// Factory function only for use by deserialization.
|
|
static FuncDecl *createDeserialized(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
bool HasImplicitSelfDecl,
|
|
DeclContext *Parent);
|
|
|
|
static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
ParamDecl *SelfDecl,
|
|
ParameterList *ParameterList,
|
|
TypeLoc FnRetType, DeclContext *Parent,
|
|
ClangNode ClangN = ClangNode());
|
|
|
|
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
|
|
|
bool isStatic() const {
|
|
return Bits.FuncDecl.IsStatic;
|
|
}
|
|
/// \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.IsStatic = IsStatic;
|
|
}
|
|
|
|
bool isMutating() const {
|
|
return getSelfAccessKind() == SelfAccessKind::Mutating;
|
|
}
|
|
bool isNonMutating() const {
|
|
return getSelfAccessKind() == SelfAccessKind::NonMutating;
|
|
}
|
|
bool isConsuming() const {
|
|
return getSelfAccessKind() == SelfAccessKind::__Consuming;
|
|
}
|
|
|
|
TypeLoc getReturnTypeLoc() const {
|
|
return FnRetType;
|
|
}
|
|
|
|
SelfAccessKind getSelfAccessKind() const {
|
|
return static_cast<SelfAccessKind>(Bits.FuncDecl.SelfAccess);
|
|
}
|
|
void setSelfAccessKind(SelfAccessKind mod) {
|
|
Bits.FuncDecl.SelfAccess = static_cast<unsigned>(mod);
|
|
}
|
|
|
|
/// \returns true if this is non-mutating due to applying a 'mutating'
|
|
/// attribute. For example a "mutating set" accessor.
|
|
bool isExplicitNonMutating() const;
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getFuncLoc() const { return FuncLoc; }
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() && !isa<AccessorDecl>(this)
|
|
? StaticLoc : FuncLoc;
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
TypeLoc &getBodyResultTypeLoc() { return FnRetType; }
|
|
const TypeLoc &getBodyResultTypeLoc() const { return FnRetType; }
|
|
|
|
/// Retrieve the result interface type of this function.
|
|
Type getResultInterfaceType() 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;
|
|
|
|
/// Determine whether this function has a dynamic \c Self return
|
|
/// type.
|
|
bool hasDynamicSelf() const { return Bits.FuncDecl.HasDynamicSelf; }
|
|
|
|
/// Set whether this function has a dynamic \c Self return or not.
|
|
void setDynamicSelf(bool hasDynamicSelf) {
|
|
Bits.FuncDecl.HasDynamicSelf = hasDynamicSelf;
|
|
}
|
|
|
|
void getLocalCaptures(SmallVectorImpl<CapturedValue> &Result) const {
|
|
return getCaptureInfo().getLocalCaptures(Result);
|
|
}
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Get the supertype method this method overrides, if any.
|
|
FuncDecl *getOverriddenDecl() const {
|
|
return cast_or_null<FuncDecl>(AbstractFunctionDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Get the property behavior this function serves as a parameter for, if
|
|
/// any.
|
|
BehaviorRecord *getParamBehavior() const {
|
|
return BehaviorParamDecl;
|
|
}
|
|
|
|
void setParamBehavior(BehaviorRecord *behavior) {
|
|
BehaviorParamDecl = behavior;
|
|
}
|
|
|
|
OperatorDecl *getOperatorDecl() const {
|
|
return Operator;
|
|
}
|
|
void setOperatorDecl(OperatorDecl *o) {
|
|
assert(isOperator() && "can't set an OperatorDecl for a non-operator");
|
|
Operator = o;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
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->getAsDeclOrDeclExtensionContext())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the function is a defer body.
|
|
bool isDeferBody() const;
|
|
|
|
/// Perform basic checking to determine whether the @IBAction attribute can
|
|
/// be applied to this function.
|
|
bool isPotentialIBActionTarget() const;
|
|
};
|
|
|
|
/// \brief 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, AddressorKind addressorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc, StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
unsigned numParameterLists, GenericParamList *genericParams,
|
|
DeclContext *parent)
|
|
: FuncDecl(DeclKind::Accessor,
|
|
staticLoc, staticSpelling, /*func loc*/ declLoc,
|
|
/*name*/ Identifier(), /*name loc*/ declLoc,
|
|
throws, throwsLoc, numParameterLists, genericParams, parent),
|
|
AccessorKeywordLoc(accessorKeywordLoc),
|
|
Storage(storage) {
|
|
Bits.AccessorDecl.AccessorKind = unsigned(accessorKind);
|
|
Bits.AccessorDecl.AddressorKind = unsigned(addressorKind);
|
|
}
|
|
|
|
static AccessorDecl *createImpl(ASTContext &ctx,
|
|
SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AddressorKind addressorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
bool hasImplicitSelfDecl,
|
|
GenericParamList *genericParams,
|
|
DeclContext *parent,
|
|
ClangNode clangNode);
|
|
|
|
public:
|
|
static AccessorDecl *createDeserialized(ASTContext &ctx,
|
|
SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AddressorKind addressorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
GenericParamList *genericParams,
|
|
bool hasImplicitSelfDecl,
|
|
DeclContext *parent);
|
|
|
|
static AccessorDecl *create(ASTContext &ctx, SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AddressorKind addressorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
GenericParamList *genericParams,
|
|
ParamDecl *selfDecl,
|
|
ParameterList *parameterList,
|
|
TypeLoc fnRetType, DeclContext *parent,
|
|
ClangNode clangNode = ClangNode());
|
|
|
|
SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; }
|
|
|
|
AbstractStorageDecl *getStorage() const {
|
|
return Storage;
|
|
}
|
|
|
|
AccessorKind getAccessorKind() const {
|
|
return AccessorKind(Bits.AccessorDecl.AccessorKind);
|
|
}
|
|
|
|
AddressorKind getAddressorKind() const {
|
|
return AddressorKind(Bits.AccessorDecl.AddressorKind);
|
|
}
|
|
|
|
bool isGetter() const { return getAccessorKind() == AccessorKind::Get; }
|
|
bool isSetter() const { return getAccessorKind() == AccessorKind::Set; }
|
|
bool isMaterializeForSet() const {
|
|
return getAccessorKind() == AccessorKind::MaterializeForSet;
|
|
}
|
|
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");
|
|
}
|
|
|
|
/// 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");
|
|
}
|
|
|
|
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->getAsDeclOrDeclExtensionContext())
|
|
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;
|
|
}
|
|
|
|
/// \brief 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;
|
|
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 *>());
|
|
}
|
|
|
|
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 *>(),
|
|
Bits.EnumCaseDecl.NumElements};
|
|
}
|
|
|
|
SourceLoc getLoc() const {
|
|
return CaseLoc;
|
|
}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumCase;
|
|
}
|
|
};
|
|
|
|
/// \brief 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 ValueDecl {
|
|
/// 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;
|
|
/// The type-checked raw value expression.
|
|
Expr *TypeCheckedRawValueExpr = nullptr;
|
|
|
|
public:
|
|
EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name,
|
|
ParameterList *Params,
|
|
SourceLoc EqualsLoc,
|
|
LiteralExpr *RawValueExpr,
|
|
DeclContext *DC)
|
|
: ValueDecl(DeclKind::EnumElement, DC, Name, IdentifierLoc),
|
|
Params(Params),
|
|
EqualsLoc(EqualsLoc),
|
|
RawValueExpr(RawValueExpr)
|
|
{
|
|
Bits.EnumElementDecl.DefaultArgumentResilienceExpansion =
|
|
static_cast<unsigned>(ResilienceExpansion::Maximal);
|
|
}
|
|
|
|
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
|
|
|
/// Returns the string for the base name, or "_" if this is unnamed.
|
|
StringRef getNameStr() const {
|
|
assert(!getFullName().isSpecial() && "Cannot get string for special names");
|
|
return hasName() ? getBaseName().getIdentifier().str() : "_";
|
|
}
|
|
|
|
/// Set the interface type of this enum element to the constructor function
|
|
/// type; (Self) -> Result or (Self) -> (Args...) -> Result.
|
|
bool computeType();
|
|
|
|
Type getArgumentInterfaceType() const;
|
|
|
|
ParameterList *getParameterList() const { return Params; }
|
|
|
|
bool hasRawValueExpr() const { return RawValueExpr; }
|
|
LiteralExpr *getRawValueExpr() const { return RawValueExpr; }
|
|
void setRawValueExpr(LiteralExpr *e) { RawValueExpr = e; }
|
|
|
|
Expr *getTypeCheckedRawValueExpr() const {
|
|
return TypeCheckedRawValueExpr;
|
|
}
|
|
void setTypeCheckedRawValueExpr(Expr *e) {
|
|
TypeCheckedRawValueExpr = e;
|
|
}
|
|
|
|
/// The ResilienceExpansion for default arguments.
|
|
///
|
|
/// In Swift 4 mode, default argument expressions are serialized, and must
|
|
/// obey the restrictions imposed upon inlinable function bodies.
|
|
ResilienceExpansion getDefaultArgumentResilienceExpansion() const {
|
|
return ResilienceExpansion(
|
|
Bits.EnumElementDecl.DefaultArgumentResilienceExpansion);
|
|
}
|
|
|
|
/// Set the ResilienceExpansion for default arguments.
|
|
void setDefaultArgumentResilienceExpansion(ResilienceExpansion expansion) {
|
|
Bits.EnumElementDecl.DefaultArgumentResilienceExpansion =
|
|
unsigned(expansion);
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumElement;
|
|
}
|
|
|
|
/// True if the case is marked 'indirect'.
|
|
bool isIndirect() const {
|
|
return getAttrs().hasAttribute<IndirectAttr>();
|
|
}
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
/// 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,
|
|
OptionalTypeKind Failability, SourceLoc FailabilityLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
ParamDecl *SelfParam, ParameterList *BodyParams,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent);
|
|
|
|
SourceLoc getConstructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getConstructorLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// getArgumentInterfaceType - get the interface type of the argument tuple
|
|
Type getArgumentInterfaceType() const;
|
|
|
|
/// \brief Get the interface type of the constructed object.
|
|
Type getResultInterfaceType() const;
|
|
|
|
/// Get the interface type of the initializing constructor.
|
|
Type getInitializerInterfaceType();
|
|
void setInitializerInterfaceType(Type t);
|
|
|
|
/// 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; }
|
|
|
|
/// 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
|
|
};
|
|
|
|
/// Determine whether the body of this constructor contains any delegating
|
|
/// or superclass initializations (\c self.init or \c super.init,
|
|
/// respectively) within its body.
|
|
///
|
|
/// \param diags If non-null, this check will ensure that the constructor
|
|
/// body is consistent in its use of delegation vs. chaining and emit any
|
|
/// diagnostics through the given diagnostic engine.
|
|
///
|
|
/// \param init If non-null and there is an explicit \c self.init or
|
|
/// \c super.init within the body, will be set to point at that
|
|
/// initializer.
|
|
BodyInitKind getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
|
|
ApplyExpr **init = nullptr) const;
|
|
|
|
/// Whether this constructor is required.
|
|
bool isRequired() const {
|
|
return getAttrs().hasAttribute<RequiredAttr>();
|
|
}
|
|
|
|
/// Determine the kind of initializer this is.
|
|
CtorInitializerKind getInitKind() const {
|
|
return static_cast<CtorInitializerKind>(Bits.ConstructorDecl.InitKind);
|
|
}
|
|
|
|
/// Set whether this is a convenience initializer.
|
|
void setInitKind(CtorInitializerKind kind) {
|
|
Bits.ConstructorDecl.InitKind = static_cast<unsigned>(kind);
|
|
}
|
|
|
|
/// 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 the failability of the initializer.
|
|
OptionalTypeKind getFailability() const {
|
|
return static_cast<OptionalTypeKind>(Bits.ConstructorDecl.Failability);
|
|
}
|
|
|
|
/// 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->getAsDeclOrDeclExtensionContext())
|
|
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, ParamDecl *selfDecl,
|
|
DeclContext *Parent);
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage() { return &SelfDecl; }
|
|
|
|
SourceLoc getDestructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getDestructorLoc(); }
|
|
SourceRange getSourceRange() 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->getAsDeclOrDeclExtensionContext())
|
|
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);
|
|
|
|
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);
|
|
|
|
|
|
SourceLoc getLoc() const { return NameLoc; }
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
ArrayRef<Relation> getLowerThan() const {
|
|
return { getLowerThanBuffer(), NumLowerThan };
|
|
}
|
|
MutableArrayRef<Relation> getMutableLowerThan() {
|
|
return { getLowerThanBuffer(), NumLowerThan };
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PrecedenceGroup;
|
|
}
|
|
};
|
|
|
|
/// Abstract base class of operator declarations.
|
|
class OperatorDecl : public Decl {
|
|
SourceLoc OperatorLoc, NameLoc;
|
|
|
|
Identifier name;
|
|
|
|
public:
|
|
OperatorDecl(DeclKind kind,
|
|
DeclContext *DC,
|
|
SourceLoc OperatorLoc,
|
|
Identifier Name,
|
|
SourceLoc NameLoc)
|
|
: Decl(kind, DC),
|
|
OperatorLoc(OperatorLoc), NameLoc(NameLoc),
|
|
name(Name) {}
|
|
|
|
SourceLoc getLoc() const { return NameLoc; }
|
|
|
|
SourceLoc getOperatorLoc() const { return OperatorLoc; }
|
|
SourceLoc getNameLoc() const { return NameLoc; }
|
|
Identifier getName() 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 /+/ : AdditivePrecedence
|
|
/// \endcode
|
|
class InfixOperatorDecl : public OperatorDecl {
|
|
SourceLoc ColonLoc, PrecedenceGroupNameLoc;
|
|
Identifier PrecedenceGroupName;
|
|
PrecedenceGroupDecl *PrecedenceGroup = nullptr;
|
|
|
|
public:
|
|
InfixOperatorDecl(DeclContext *DC,
|
|
SourceLoc operatorLoc,
|
|
Identifier name,
|
|
SourceLoc nameLoc,
|
|
SourceLoc colonLoc,
|
|
Identifier precedenceGroupName,
|
|
SourceLoc precedenceGroupNameLoc)
|
|
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
|
|
ColonLoc(colonLoc), PrecedenceGroupNameLoc(precedenceGroupNameLoc),
|
|
PrecedenceGroupName(precedenceGroupName) {
|
|
}
|
|
|
|
SourceLoc getEndLoc() const {
|
|
if (PrecedenceGroupName.empty())
|
|
return getNameLoc();
|
|
return PrecedenceGroupNameLoc;
|
|
}
|
|
SourceRange getSourceRange() const {
|
|
return { getOperatorLoc(), getEndLoc() };
|
|
}
|
|
|
|
SourceLoc getColonLoc() const { return ColonLoc; }
|
|
SourceLoc getPrecedenceGroupNameLoc() const { return PrecedenceGroupNameLoc; }
|
|
|
|
Identifier getPrecedenceGroupName() const { return PrecedenceGroupName; }
|
|
PrecedenceGroupDecl *getPrecedenceGroup() const { return PrecedenceGroup; }
|
|
void setPrecedenceGroup(PrecedenceGroupDecl *PGD) {
|
|
PrecedenceGroup = PGD;
|
|
}
|
|
|
|
/// True if this decl's attributes conflict with those declared by another
|
|
/// operator.
|
|
bool conflictsWith(InfixOperatorDecl *other) {
|
|
return getPrecedenceGroup() != other->getPrecedenceGroup();
|
|
}
|
|
|
|
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() };
|
|
}
|
|
|
|
/// True if this decl's attributes conflict with those declared by another
|
|
/// PrefixOperatorDecl.
|
|
bool conflictsWith(PrefixOperatorDecl *other) {
|
|
return false;
|
|
}
|
|
|
|
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() };
|
|
}
|
|
|
|
/// True if this decl's attributes conflict with those declared by another
|
|
/// PostfixOperatorDecl.
|
|
bool conflictsWith(PostfixOperatorDecl *other) {
|
|
return false;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PostfixOperator;
|
|
}
|
|
};
|
|
|
|
/// 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();
|
|
}
|
|
public:
|
|
static MissingMemberDecl *
|
|
forMethod(ASTContext &ctx, DeclContext *DC, DeclName name,
|
|
bool hasNormalVTableEntry) {
|
|
assert(!name || name.isCompoundName());
|
|
return new (ctx) MissingMemberDecl(DC, name, hasNormalVTableEntry, 0);
|
|
}
|
|
|
|
static MissingMemberDecl *
|
|
forInitializer(ASTContext &ctx, DeclContext *DC, DeclName name,
|
|
bool hasNormalVTableEntry,
|
|
bool hasAllocatingVTableEntry) {
|
|
unsigned entries = hasNormalVTableEntry + hasAllocatingVTableEntry;
|
|
return new (ctx) MissingMemberDecl(DC, name, entries, 0);
|
|
}
|
|
|
|
static MissingMemberDecl *
|
|
forStoredProperty(ASTContext &ctx, DeclContext *DC, DeclName name) {
|
|
return new (ctx) MissingMemberDecl(DC, name, 0, 1);
|
|
}
|
|
|
|
DeclName getFullName() const {
|
|
return Name;
|
|
}
|
|
|
|
unsigned getNumberOfVTableEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfVTableEntries;
|
|
}
|
|
|
|
unsigned getNumberOfFieldOffsetVectorEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfFieldOffsetVectorEntries;
|
|
}
|
|
|
|
SourceLoc getLoc() const {
|
|
return SourceLoc();
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange();
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::MissingMember;
|
|
}
|
|
};
|
|
|
|
inline bool ValueDecl::isSettable(const DeclContext *UseDC,
|
|
const DeclRefExpr *base) const {
|
|
if (auto vd = dyn_cast<VarDecl>(this)) {
|
|
return vd->isSettable(UseDC, base);
|
|
} else if (auto sd = dyn_cast<SubscriptDecl>(this)) {
|
|
return sd->isSettable();
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
inline Optional<VarDecl *>
|
|
NominalTypeDecl::ToStoredProperty::operator()(Decl *decl) const {
|
|
if (auto var = dyn_cast<VarDecl>(decl)) {
|
|
if (!var->isStatic() && var->hasStorage() &&
|
|
(!skipUserInaccessible || var->isUserAccessible()))
|
|
return var;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
inline Optional<Decl *>
|
|
NominalTypeDecl::ToStoredPropertyOrMissingMemberPlaceholder
|
|
::operator()(Decl *decl) const {
|
|
if (auto var = dyn_cast<VarDecl>(decl)) {
|
|
if (!var->isStatic() && var->hasStorage())
|
|
return var;
|
|
}
|
|
if (auto missing = dyn_cast<MissingMemberDecl>(decl)) {
|
|
if (missing->getNumberOfFieldOffsetVectorEntries() > 0)
|
|
return missing;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
inline void
|
|
AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) {
|
|
Accessors.setInt(accessLevel);
|
|
if (auto setter = getSetter())
|
|
setter->overwriteAccess(accessLevel);
|
|
if (auto materializeForSet = getMaterializeForSetFunc())
|
|
materializeForSet->overwriteAccess(accessLevel);
|
|
if (auto mutableAddressor = getMutableAddressor())
|
|
mutableAddressor->overwriteAccess(accessLevel);
|
|
}
|
|
|
|
inline bool AbstractStorageDecl::isStatic() const {
|
|
if (auto var = dyn_cast<VarDecl>(this)) {
|
|
return var->isStatic();
|
|
}
|
|
|
|
// Currently, subscripts are never static.
|
|
return false;
|
|
}
|
|
|
|
/// 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 Decl::isPotentiallyOverridable() const {
|
|
if (isa<VarDecl>(this) ||
|
|
isa<SubscriptDecl>(this) ||
|
|
isa<FuncDecl>(this) ||
|
|
isa<DestructorDecl>(this)) {
|
|
return getDeclContext()->getAsClassOrClassExtensionContext();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
inline GenericParamKey::GenericParamKey(const GenericTypeParamDecl *d)
|
|
: 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::isExtensionContext() const {
|
|
if (auto D = getAsDeclOrDeclExtensionContext())
|
|
return ExtensionDecl::classof(D);
|
|
return false;
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
|
|
/// Determine the default argument kind and type for the given argument index
|
|
/// in this declaration, which must be a function or constructor.
|
|
///
|
|
/// \param Index The index of the argument for which we are querying the
|
|
/// default argument.
|
|
///
|
|
/// \returns the default argument kind and, if there is a default argument,
|
|
/// the type of the corresponding parameter.
|
|
std::pair<DefaultArgumentKind, Type>
|
|
getDefaultArgumentInfo(ValueDecl *source, unsigned Index);
|
|
|
|
/// Display ValueDecl subclasses.
|
|
void simple_display(llvm::raw_ostream &out, const ValueDecl *decl);
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|