mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Pass through the location of the equal '=' token for pattern binding decl entries, and use this location for the immediate deallocation diagnostic. Previously, we were just diagnosing on the start of the initialiser expression. Additionally, this commit moves the call to `diagnoseUnownedImmediateDeallocation` from `typeCheckBinding` to `typeCheckPatternBinding`. This not only gives us easier access to the PBD entry, but also avoids calling the diagnostic logic for statement conditions such as `if let x = <expr>`. We currently never diagnose on these anyway, as the 'weak' and 'unowned' keywords cannot be applied to such bindings. Resolves [SR-7340](https://bugs.swift.org/browse/SR-7340).
6629 lines
225 KiB
C++
6629 lines
225 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/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,
|
|
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 {
|
|
enum class ValidationState {
|
|
Unchecked,
|
|
Checking,
|
|
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+5+1+1+1+1+1+1,
|
|
/// \see AbstractFunctionDecl::BodyKind
|
|
BodyKind : 3,
|
|
|
|
/// Import as member status.
|
|
IAMStatus : 8,
|
|
|
|
/// Number of curried parameter lists.
|
|
NumParameterLists : 5,
|
|
|
|
/// 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, 3+3,
|
|
/// The kind of accessor this is.
|
|
AccessorKind : 3,
|
|
|
|
/// 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;
|
|
|
|
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.
|
|
ModuleDecl *getModuleContext() const;
|
|
|
|
/// getASTContext - Return the ASTContext that this decl lives in.
|
|
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;
|
|
}
|
|
|
|
/// Whether the declaration has a valid interface type and
|
|
/// generic signature.
|
|
bool isBeingValidated() const {
|
|
return Bits.Decl.ValidationState == unsigned(ValidationState::Checking);
|
|
}
|
|
|
|
/// Toggle whether or not the declaration is being validated.
|
|
void setIsBeingValidated(bool ibv = true) {
|
|
if (ibv) {
|
|
assert(Bits.Decl.ValidationState == unsigned(ValidationState::Unchecked));
|
|
Bits.Decl.ValidationState = unsigned(ValidationState::Checking);
|
|
} else {
|
|
assert(Bits.Decl.ValidationState == unsigned(ValidationState::Checking));
|
|
Bits.Decl.ValidationState = unsigned(ValidationState::Checked);
|
|
}
|
|
}
|
|
|
|
bool hasValidationStarted() const {
|
|
return Bits.Decl.ValidationState >= unsigned(ValidationState::Checking);
|
|
}
|
|
|
|
/// Manually indicate that validation has started for the declaration.
|
|
///
|
|
/// This is implied by setIsBeingValidated(true) (i.e. starting validation)
|
|
/// and so rarely needs to be called directly.
|
|
void setValidationStarted() {
|
|
if (Bits.Decl.ValidationState != unsigned(ValidationState::Checking))
|
|
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.
|
|
ClangNode getClangNode() const {
|
|
if (!Bits.Decl.FromClang)
|
|
return ClangNode();
|
|
|
|
return getClangNodeImpl();
|
|
}
|
|
|
|
/// \brief Retrieve the Clang declaration from which this declaration was
|
|
/// synthesized, if any.
|
|
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.
|
|
const clang::MacroInfo *getClangMacro() {
|
|
if (!Bits.Decl.FromClang)
|
|
return nullptr;
|
|
|
|
return getClangNodeImpl().getAsMacro();
|
|
}
|
|
|
|
/// \brief Return the GenericContext if the Decl has one.
|
|
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.
|
|
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 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.
|
|
bool hasValidSignature() const {
|
|
return hasValidationStarted() && !isBeingValidated();
|
|
}
|
|
|
|
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;
|
|
} LazySemanticInfo;
|
|
|
|
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;
|
|
}
|
|
|
|
// 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.
|
|
ArrayRef<ValueDecl *> getOverriddenDecls() const;
|
|
|
|
/// Set the declaration that this declaration overrides.
|
|
void setOverriddenDecl(ValueDecl *overridden) {
|
|
(void)setOverriddenDecls(overridden);
|
|
}
|
|
|
|
/// Set the declarations that this declaration overrides.
|
|
///
|
|
/// \returns the ASTContext-allocated version of the array of overridden
|
|
/// declarations.
|
|
ArrayRef<ValueDecl *> 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 {
|
|
return getAttrs().hasAttribute<DynamicAttr>();
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// computeType - Compute the type (and declared type) of this associated
|
|
/// type; can only be called after the alias type has been resolved.
|
|
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.
|
|
CastArrayRefView<ValueDecl *, AssociatedTypeDecl>
|
|
getOverriddenDecls() const {
|
|
return CastArrayRefView<ValueDecl *, AssociatedTypeDecl>(
|
|
AbstractTypeParamDecl::getOverriddenDecls());
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/// Compute the type of this nominal 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 'mutableAddress' accessors if
|
|
/// it exists; this is only valid on a declaration with addressors.
|
|
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 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 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; }
|
|
|
|
/// \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 *);
|
|
|
|
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,
|
|
unsigned NumParameterLists,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent),
|
|
ValueDecl(Kind, Parent, Name, NameLoc),
|
|
Body(nullptr), ThrowsLoc(ThrowsLoc) {
|
|
setBodyKind(BodyKind::None);
|
|
setGenericParams(GenericParams);
|
|
Bits.AbstractFunctionDecl.NumParameterLists = NumParameterLists;
|
|
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;
|
|
|
|
// Verify no bitfield truncation.
|
|
assert(Bits.AbstractFunctionDecl.NumParameterLists == NumParameterLists);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
public:
|
|
/// 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:
|
|
/// 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;
|
|
|
|
/// \brief Returns the "natural" number of argument clauses taken by this
|
|
/// function. This value is one for free-standing functions, and two for
|
|
/// methods.
|
|
unsigned getNumParameterLists() const {
|
|
return Bits.AbstractFunctionDecl.NumParameterLists;
|
|
}
|
|
|
|
/// \brief Returns the parameter pattern(s) for the function definition that
|
|
/// determine the parameter names bound in the function body.
|
|
///
|
|
/// The number of "top-level" elements in this pattern will match the number
|
|
/// of argument names in the compound name of the function or constructor.
|
|
MutableArrayRef<ParameterList *> getParameterLists();
|
|
ArrayRef<const ParameterList *> getParameterLists() const {
|
|
auto paramLists =
|
|
const_cast<AbstractFunctionDecl *>(this)->getParameterLists();
|
|
return ArrayRef<const ParameterList *>(paramLists.data(),paramLists.size());
|
|
}
|
|
ParameterList *getParameterList(unsigned i) {
|
|
return getParameterLists()[i];
|
|
}
|
|
const ParameterList *getParameterList(unsigned i) const {
|
|
return getParameterLists()[i];
|
|
}
|
|
|
|
/// \brief This method returns the implicit 'self' decl.
|
|
///
|
|
/// Note that some functions don't have an implicit 'self' decl, for example,
|
|
/// free functions. In this case nullptr is returned.
|
|
const ParamDecl *getImplicitSelfDecl() const {
|
|
return const_cast<AbstractFunctionDecl*>(this)->getImplicitSelfDecl();
|
|
}
|
|
ParamDecl *getImplicitSelfDecl();
|
|
|
|
/// 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:
|
|
ParameterList **getParameterListBuffer(); // defined inline below
|
|
ParameterList * const *getParameterListBuffer() const {
|
|
return const_cast<FuncDecl*>(this)->getParameterListBuffer();
|
|
}
|
|
|
|
FuncDecl(DeclKind Kind,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
unsigned NumParameterLists,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: AbstractFunctionDecl(Kind, Parent,
|
|
Name, NameLoc,
|
|
Throws, ThrowsLoc,
|
|
NumParameterLists, GenericParams),
|
|
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
|
|
assert(!Name.getBaseName().isSpecial());
|
|
|
|
Bits.FuncDecl.IsStatic =
|
|
StaticLoc.isValid() || StaticSpelling != StaticSpellingKind::None;
|
|
Bits.FuncDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
assert(NumParameterLists > 0 && "Must have at least an empty tuple arg");
|
|
|
|
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,
|
|
unsigned NumParameterLists,
|
|
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,
|
|
unsigned NumParameterLists,
|
|
DeclContext *Parent);
|
|
|
|
static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
ArrayRef<ParameterList *> ParameterLists,
|
|
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);
|
|
}
|
|
|
|
/// \brief Returns the parameter lists(s) for the function definition.
|
|
///
|
|
/// The number of "top-level" elements will match the number of argument names
|
|
/// in the compound name of the function or constructor.
|
|
MutableArrayRef<ParameterList *> getParameterLists() {
|
|
return {getParameterListBuffer(), getNumParameterLists()};
|
|
}
|
|
ArrayRef<const ParameterList *> getParameterLists() const {
|
|
return {getParameterListBuffer(), getNumParameterLists()};
|
|
}
|
|
ParameterList *getParameterList(unsigned i) {
|
|
return getParameterLists()[i];
|
|
}
|
|
const ParameterList *getParameterList(unsigned i) const {
|
|
return getParameterLists()[i];
|
|
}
|
|
|
|
/// \returns true if this is non-mutating due to applying a 'mutating'
|
|
/// attribute. For example a "mutating set" accessor.
|
|
bool isExplicitNonMutating() const;
|
|
|
|
void setDeserializedSignature(ArrayRef<ParameterList *> ParameterLists,
|
|
TypeLoc FnRetType);
|
|
|
|
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);
|
|
}
|
|
|
|
/// 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,
|
|
unsigned numParameterLists,
|
|
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,
|
|
unsigned numParameterLists,
|
|
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,
|
|
ArrayRef<ParameterList *> parameterLists,
|
|
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 {
|
|
return getAccessorKind() == AccessorKind::DidSet ||
|
|
getAccessorKind() == AccessorKind::WillSet;
|
|
}
|
|
|
|
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 ParameterList **FuncDecl::getParameterListBuffer() {
|
|
if (!isa<AccessorDecl>(this)) {
|
|
assert(getKind() == DeclKind::Func && "no new kinds of functions");
|
|
return reinterpret_cast<ParameterList**>(this+1);
|
|
}
|
|
return reinterpret_cast<ParameterList**>(static_cast<AccessorDecl*>(this)+1);
|
|
}
|
|
|
|
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() : "_";
|
|
}
|
|
|
|
/// \returns false if there was an error during the computation rendering the
|
|
/// EnumElementDecl invalid, true otherwise.
|
|
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;
|
|
|
|
ParameterList *ParameterLists[2];
|
|
|
|
/// 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);
|
|
|
|
void setParameterLists(ParamDecl *selfParam, ParameterList *bodyParams);
|
|
|
|
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; }
|
|
|
|
MutableArrayRef<ParameterList *> getParameterLists() {
|
|
return { ParameterLists, 2 };
|
|
}
|
|
ArrayRef<const ParameterList *> getParameterLists() const {
|
|
return AbstractFunctionDecl::getParameterLists();
|
|
}
|
|
ParameterList *getParameterList(unsigned i) {
|
|
return getParameterLists()[i];
|
|
}
|
|
const ParameterList *getParameterList(unsigned i) const {
|
|
return getParameterLists()[i];
|
|
}
|
|
|
|
/// Returns the normal parameters to the initializer, not including self.
|
|
ParameterList *getParameters() { return ParameterLists[1]; }
|
|
|
|
/// Returns the normal parameters to the initializer, not including self.
|
|
const ParameterList *getParameters() const { return ParameterLists[1]; }
|
|
|
|
|
|
/// 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 {
|
|
ParameterList *SelfParameter;
|
|
public:
|
|
DestructorDecl(SourceLoc DestructorLoc, ParamDecl *selfDecl,
|
|
DeclContext *Parent);
|
|
|
|
void setSelfDecl(ParamDecl *selfDecl);
|
|
|
|
MutableArrayRef<ParameterList *> getParameterLists() {
|
|
return { &SelfParameter, 1 };
|
|
}
|
|
ArrayRef<const ParameterList *> getParameterLists() const {
|
|
return { &SelfParameter, 1 };
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
inline MutableArrayRef<ParameterList *>
|
|
AbstractFunctionDecl::getParameterLists() {
|
|
switch (getKind()) {
|
|
default: llvm_unreachable("Unknown AbstractFunctionDecl!");
|
|
case DeclKind::Constructor:
|
|
return cast<ConstructorDecl>(this)->getParameterLists();
|
|
case DeclKind::Destructor:
|
|
return cast<DestructorDecl>(this)->getParameterLists();
|
|
case DeclKind::Func:
|
|
case DeclKind::Accessor:
|
|
return cast<FuncDecl>(this)->getParameterLists();
|
|
}
|
|
}
|
|
|
|
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
|