mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The moment you've all been waiting for... Define InterfaceTypeRequest and use it to, well, compute the interface type. This naturally widens the few cycles that we pick up with the request evaluator. There is still a lot of work to get done here, mostly around scaling back all of the ad-hoc circularity checks around the interface type computation. It would also be great to improve the circularity diagnostics.
7366 lines
251 KiB
C++
7366 lines
251 KiB
C++
//===--- Decl.h - Swift Language Declaration ASTs ---------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the Decl class and subclasses.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_DECL_H
|
|
#define SWIFT_DECL_H
|
|
|
|
#include "swift/AST/AccessScope.h"
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/CaptureInfo.h"
|
|
#include "swift/AST/ClangNode.h"
|
|
#include "swift/AST/ConcreteDeclRef.h"
|
|
#include "swift/AST/DefaultArgumentKind.h"
|
|
#include "swift/AST/DiagnosticConsumer.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/GenericParamKey.h"
|
|
#include "swift/AST/IfConfigClause.h"
|
|
#include "swift/AST/LayoutConstraint.h"
|
|
#include "swift/AST/StorageImpl.h"
|
|
#include "swift/AST/TypeAlignments.h"
|
|
#include "swift/AST/TypeWalker.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/Witness.h"
|
|
#include "swift/Basic/ArrayRefView.h"
|
|
#include "swift/Basic/Compiler.h"
|
|
#include "swift/Basic/InlineBitfield.h"
|
|
#include "swift/Basic/NullablePtr.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 AvailabilityContext;
|
|
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 ModuleDecl;
|
|
class NamedPattern;
|
|
class EnumCaseDecl;
|
|
class EnumElementDecl;
|
|
class ParameterList;
|
|
class ParameterTypeFlags;
|
|
class Pattern;
|
|
struct PrintOptions;
|
|
struct PropertyWrapperBackingPropertyInfo;
|
|
struct PropertyWrapperTypeInfo;
|
|
struct PropertyWrapperMutability;
|
|
class ProtocolDecl;
|
|
class ProtocolType;
|
|
struct RawComment;
|
|
enum class ResilienceExpansion : unsigned;
|
|
class TypeAliasDecl;
|
|
class Stmt;
|
|
class SubscriptDecl;
|
|
class UnboundGenericType;
|
|
class ValueDecl;
|
|
class VarDecl;
|
|
class OpaqueReturnTypeRepr;
|
|
|
|
namespace ast_scope {
|
|
class AbstractPatternEntryScope;
|
|
class PatternEntryDeclScope;
|
|
class PatternEntryInitializerScope;
|
|
} // namespace ast_scope
|
|
|
|
enum class DeclKind : uint8_t {
|
|
#define DECL(Id, Parent) Id,
|
|
#define LAST_DECL(Id) Last_Decl = Id,
|
|
#define DECL_RANGE(Id, FirstId, LastId) \
|
|
First_##Id##Decl = FirstId, Last_##Id##Decl = LastId,
|
|
#include "swift/AST/DeclNodes.def"
|
|
};
|
|
enum : unsigned { NumDeclKindBits =
|
|
countBitsUsed(static_cast<unsigned>(DeclKind::Last_Decl)) };
|
|
|
|
|
|
/// Fine-grained declaration kind that provides a description of the
|
|
/// kind of entity a declaration represents, as it would be used in
|
|
/// diagnostics.
|
|
///
|
|
/// For example, \c FuncDecl is a single declaration class, but it has
|
|
/// several descriptive entries depending on whether it is an
|
|
/// operator, global function, local function, method, (observing)
|
|
/// accessor, etc.
|
|
enum class DescriptiveDeclKind : uint8_t {
|
|
Import,
|
|
Extension,
|
|
EnumCase,
|
|
TopLevelCode,
|
|
IfConfig,
|
|
PoundDiagnostic,
|
|
PatternBinding,
|
|
Var,
|
|
Param,
|
|
Let,
|
|
Property,
|
|
StaticProperty,
|
|
ClassProperty,
|
|
InfixOperator,
|
|
PrefixOperator,
|
|
PostfixOperator,
|
|
PrecedenceGroup,
|
|
TypeAlias,
|
|
GenericTypeParam,
|
|
AssociatedType,
|
|
Type,
|
|
Enum,
|
|
Struct,
|
|
Class,
|
|
Protocol,
|
|
GenericEnum,
|
|
GenericStruct,
|
|
GenericClass,
|
|
GenericType,
|
|
Subscript,
|
|
StaticSubscript,
|
|
ClassSubscript,
|
|
Constructor,
|
|
Destructor,
|
|
LocalFunction,
|
|
GlobalFunction,
|
|
OperatorFunction,
|
|
Method,
|
|
StaticMethod,
|
|
ClassMethod,
|
|
Getter,
|
|
Setter,
|
|
Addressor,
|
|
MutableAddressor,
|
|
ReadAccessor,
|
|
ModifyAccessor,
|
|
WillSet,
|
|
DidSet,
|
|
EnumElement,
|
|
Module,
|
|
MissingMember,
|
|
Requirement,
|
|
OpaqueResultType,
|
|
OpaqueVarType
|
|
};
|
|
|
|
/// 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 is a enum element.
|
|
unsigned IsEnumElement : 1;
|
|
|
|
/// Whether this is a nominal type.
|
|
unsigned IsNominal : 1;
|
|
|
|
/// Whether this is a type alias.
|
|
unsigned IsTypeAlias : 1;
|
|
|
|
/// Whether this signature is part of a protocol extension.
|
|
unsigned InProtocolExtension : 1;
|
|
|
|
/// Whether this signature is of a member defined in an extension of a generic
|
|
/// type.
|
|
unsigned InExtensionOfGenericType : 1;
|
|
|
|
/// Whether this declaration has an opaque return type.
|
|
unsigned HasOpaqueReturnType : 1;
|
|
|
|
OverloadSignature()
|
|
: UnaryOperator(UnaryOperatorKind::None), IsInstanceMember(false),
|
|
IsVariable(false), IsFunction(false), InProtocolExtension(false),
|
|
InExtensionOfGenericType(false), HasOpaqueReturnType(false) {}
|
|
};
|
|
|
|
/// Determine whether two overload signatures conflict.
|
|
///
|
|
/// \param sig1 The overload signature of the first declaration.
|
|
/// \param sig2 The overload signature of the second declaration.
|
|
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
|
|
/// will be allowed to conflict with members of protocol declarations.
|
|
bool conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2,
|
|
bool skipProtocolExtensionCheck = false);
|
|
|
|
/// Determine whether two overload signatures and overload types conflict.
|
|
///
|
|
/// \param ctx The AST context.
|
|
/// \param sig1 The overload signature of the first declaration.
|
|
/// \param sig1Type The overload type of the first declaration.
|
|
/// \param sig2 The overload signature of the second declaration.
|
|
/// \param sig2Type The overload type of the second declaration.
|
|
/// \param wouldConflictInSwift5 If non-null, the referenced boolean will be set
|
|
/// to \c true iff the function returns \c false for this version of
|
|
/// Swift, but the given overloads will conflict in Swift 5 mode.
|
|
/// \param skipProtocolExtensionCheck If \c true, members of protocol extensions
|
|
/// will be allowed to conflict with members of protocol declarations.
|
|
bool conflicting(ASTContext &ctx,
|
|
const OverloadSignature& sig1, CanType sig1Type,
|
|
const OverloadSignature& sig2, CanType sig2Type,
|
|
bool *wouldConflictInSwift5 = nullptr,
|
|
bool skipProtocolExtensionCheck = false);
|
|
|
|
/// Decl - Base class for all declarations in Swift.
|
|
class alignas(1 << DeclAlignInBits) Decl {
|
|
public:
|
|
enum class ValidationState {
|
|
Unchecked,
|
|
Checking,
|
|
Checked,
|
|
};
|
|
|
|
protected:
|
|
union { uint64_t OpaqueBits;
|
|
|
|
SWIFT_INLINE_BITFIELD_BASE(Decl, bitmax(NumDeclKindBits,8)+1+1+1+1+2+1,
|
|
Kind : bitmax(NumDeclKindBits,8),
|
|
|
|
/// Whether this declaration is invalid.
|
|
Invalid : 1,
|
|
|
|
/// Whether this declaration was implicitly created, e.g.,
|
|
/// an implicit constructor in a struct.
|
|
Implicit : 1,
|
|
|
|
/// Whether this declaration was mapped directly from a Clang AST.
|
|
///
|
|
/// Use getClangNode() to retrieve the corresponding Clang AST.
|
|
FromClang : 1,
|
|
|
|
/// The validation state of this declaration.
|
|
ValidationState : 2,
|
|
|
|
/// 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,
|
|
/// Whether this pattern binding declares static variables.
|
|
IsStatic : 1,
|
|
|
|
/// Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
: NumPadBits,
|
|
|
|
/// The number of pattern binding declarations.
|
|
NumPatternEntries : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(EnumCaseDecl, Decl, 32,
|
|
: NumPadBits,
|
|
|
|
/// The number of tail-allocated element pointers.
|
|
NumElements : 32
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ValueDecl, Decl, 1+1+1,
|
|
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,
|
|
/// Whether this property is a type property (currently unfortunately
|
|
/// called 'static').
|
|
IsStatic : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(VarDecl, AbstractStorageDecl, 1+1+1+1+1+1,
|
|
/// Encodes whether this is a 'let' binding.
|
|
Introducer : 1,
|
|
|
|
/// Whether this declaration was an element of a capture list.
|
|
IsCaptureList : 1,
|
|
|
|
/// 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,
|
|
|
|
/// Whether this is a property used in expressions in the debugger.
|
|
/// It is up to the debugger to instruct SIL how to access this variable.
|
|
IsDebuggerVar : 1,
|
|
|
|
/// Whether this is the backing storage for a lazy property.
|
|
IsLazyStorageProperty : 1,
|
|
|
|
/// Whether this is the backing storage for a property wrapper.
|
|
IsPropertyWrapperBackingProperty : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ParamDecl, VarDecl, 1+2+NumDefaultArgumentKindBits,
|
|
/// Whether we've computed the specifier yet.
|
|
SpecifierComputed : 1,
|
|
|
|
/// The specifier associated with this parameter. This determines
|
|
/// the storage semantics of the value e.g. mutability.
|
|
Specifier : 2,
|
|
|
|
/// Information about a symbolic default argument, like #file.
|
|
defaultArgumentKind : NumDefaultArgumentKindBits
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
|
|
StaticSpelling : 2
|
|
);
|
|
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1,
|
|
/// \see AbstractFunctionDecl::BodyKind
|
|
BodyKind : 3,
|
|
|
|
/// Import as member status.
|
|
IAMStatus : 8,
|
|
|
|
/// Whether the function has an implicit 'self' parameter.
|
|
HasImplicitSelfDecl : 1,
|
|
|
|
/// Whether we are overridden later.
|
|
Overridden : 1,
|
|
|
|
/// Whether the function body throws.
|
|
Throws : 1,
|
|
|
|
/// Whether this member was synthesized as part of a derived
|
|
/// protocol conformance.
|
|
Synthesized : 1,
|
|
|
|
/// Whether this member's body consists of a single expression.
|
|
HasSingleExpressionBody : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(FuncDecl, AbstractFunctionDecl, 1+1+2+1+1+2,
|
|
/// Whether we've computed the 'static' flag yet.
|
|
IsStaticComputed : 1,
|
|
|
|
/// Whether this function is a 'static' method.
|
|
IsStatic : 1,
|
|
|
|
/// Whether 'static' or 'class' was used.
|
|
StaticSpelling : 2,
|
|
|
|
/// Whether we are statically dispatched even if overridable
|
|
ForcedStaticDispatch : 1,
|
|
|
|
/// Whether we've computed the 'self' access kind yet.
|
|
SelfAccessComputed : 1,
|
|
|
|
/// Backing bits for 'self' access kind.
|
|
SelfAccess : 2
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(AccessorDecl, FuncDecl, 4+1+1,
|
|
/// The kind of accessor this is.
|
|
AccessorKind : 4,
|
|
|
|
/// Whether the accessor is transparent.
|
|
IsTransparent : 1,
|
|
|
|
/// Whether we have computed the above.
|
|
IsTransparentComputed : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ConstructorDecl, AbstractFunctionDecl, 3+1+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,
|
|
|
|
/// Whether this constructor can fail, by building an Optional type.
|
|
Failable : 1,
|
|
|
|
/// Whether this initializer is a stub placed into a subclass to
|
|
/// catch invalid delegations to a designated initializer not
|
|
/// overridden by the subclass. A stub will always trap at runtime.
|
|
///
|
|
/// Initializer stubs can be invoked from Objective-C or through
|
|
/// the Objective-C runtime; there is no way to directly express
|
|
/// an object construction that will invoke a stub.
|
|
HasStubImplementation : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_EMPTY(TypeDecl, ValueDecl);
|
|
SWIFT_INLINE_BITFIELD_EMPTY(AbstractTypeParamDecl, TypeDecl);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(GenericTypeParamDecl, AbstractTypeParamDecl, 16+16,
|
|
: NumPadBits,
|
|
|
|
Depth : 16,
|
|
Index : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_EMPTY(GenericTypeDecl, TypeDecl);
|
|
|
|
SWIFT_INLINE_BITFIELD(TypeAliasDecl, GenericTypeDecl, 1+1,
|
|
/// Whether the typealias forwards perfectly to its underlying type.
|
|
IsCompatibilityAlias : 1,
|
|
/// Whether this was a global typealias synthesized by the debugger.
|
|
IsDebuggerAlias : 1
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(NominalTypeDecl, GenericTypeDecl, 1+1,
|
|
/// 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
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD_FULL(ProtocolDecl, NominalTypeDecl, 1+1+1+1+1+1+1+2+1+1+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,
|
|
|
|
/// The stage of the circularity check for this protocol.
|
|
Circularity : 2,
|
|
|
|
/// Whether we've computed the inherited protocols list yet.
|
|
InheritedProtocolsValid : 1,
|
|
|
|
/// Whether we have a lazy-loaded requirement signature.
|
|
HasLazyRequirementSignature : 1,
|
|
|
|
: NumPadBits,
|
|
|
|
/// If this is a compiler-known protocol, this will be a KnownProtocolKind
|
|
/// value, plus one. Otherwise, it will be 0.
|
|
KnownProtocol : 8, // '8' for speed. This only needs 6.
|
|
|
|
/// The number of requirements in the requirement signature.
|
|
NumRequirementsInSignature : 16
|
|
);
|
|
|
|
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 2+1+2+1+7+1+1+1+1+1+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,
|
|
|
|
/// \see ClassDecl::getEmittedMembers()
|
|
HasForcedEmittedMembers : 1,
|
|
|
|
HasMissingDesignatedInitializers : 1,
|
|
ComputedHasMissingDesignatedInitializers : 1,
|
|
|
|
HasMissingVTableEntries : 1,
|
|
ComputedHasMissingVTableEntries : 1,
|
|
|
|
/// Whether instances of this class are incompatible
|
|
/// with weak and unowned references.
|
|
IsIncompatibleWithWeakReferences : 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(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1,
|
|
/// If the module was or is being compiled with `-enable-testing`.
|
|
TestingEnabled : 1,
|
|
|
|
/// If the module failed to load
|
|
FailedToLoad : 1,
|
|
|
|
/// Whether the module is resilient.
|
|
///
|
|
/// \sa ResilienceStrategy
|
|
RawResilienceStrategy : 1,
|
|
|
|
/// Whether all imports have been resolved. Used to detect circular imports.
|
|
HasResolvedImports : 1,
|
|
|
|
/// If the module was or is being compiled with `-enable-private-imports`.
|
|
PrivateImportsEnabled : 1,
|
|
|
|
/// If the module is compiled with `-enable-implicit-dynamic`.
|
|
ImplicitDynamicEnabled : 1,
|
|
|
|
/// Whether the module is a system module.
|
|
IsSystemModule : 1,
|
|
|
|
/// Whether the module was imported from Clang (or, someday, maybe another
|
|
/// language).
|
|
IsNonSwiftModule : 1
|
|
);
|
|
|
|
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;
|
|
SourceLoc getLocFromSource() const;
|
|
|
|
struct CachedExternalSourceLocs {
|
|
SourceLoc Loc;
|
|
SourceLoc StartLoc;
|
|
SourceLoc EndLoc;
|
|
};
|
|
mutable CachedExternalSourceLocs const *CachedLocs = nullptr;
|
|
const CachedExternalSourceLocs *calculateSerializedLocs() const;
|
|
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.ValidationState = unsigned(ValidationState::Unchecked);
|
|
Bits.Decl.EscapedFromIfConfig = false;
|
|
}
|
|
|
|
/// Get the Clang node associated with this declaration.
|
|
ClangNode getClangNodeImpl() const;
|
|
|
|
/// Set the Clang node associated with this declaration.
|
|
void setClangNode(ClangNode Node);
|
|
|
|
void updateClangNode(ClangNode node) {
|
|
assert(hasClangNode());
|
|
setClangNode(node);
|
|
}
|
|
friend class ClangImporter;
|
|
|
|
DeclContext *getDeclContextForModule() const;
|
|
|
|
public:
|
|
DeclKind getKind() const { return DeclKind(Bits.Decl.Kind); }
|
|
|
|
/// Retrieve the name of the given declaration kind.
|
|
///
|
|
/// This name should only be used for debugging dumps and other
|
|
/// developer aids, and should never be part of a diagnostic or exposed
|
|
/// to the user of the compiler in any way.
|
|
static StringRef getKindName(DeclKind K);
|
|
|
|
/// Retrieve the descriptive kind for this declaration.
|
|
DescriptiveDeclKind getDescriptiveKind() const;
|
|
|
|
/// Produce a name for the given descriptive declaration kind, which
|
|
/// is suitable for use in diagnostics.
|
|
static StringRef getDescriptiveKindName(DescriptiveDeclKind K);
|
|
|
|
/// Whether swift users should be able to access this decl. For instance,
|
|
/// var a.storage for lazy var a is an inaccessible decl. An inaccessible decl
|
|
/// has to be implicit; but an implicit decl does not have to be inaccessible,
|
|
/// for instance, self.
|
|
bool isUserAccessible() const;
|
|
|
|
/// Determine if the decl can have a comment. If false, a comment will
|
|
/// not be serialized.
|
|
bool canHaveComment() const;
|
|
|
|
LLVM_READONLY
|
|
DeclContext *getDeclContext() const {
|
|
if (auto dc = Context.dyn_cast<DeclContext *>())
|
|
return dc;
|
|
|
|
return getDeclContextForModule();
|
|
}
|
|
void setDeclContext(DeclContext *DC);
|
|
|
|
/// Retrieve the innermost declaration context corresponding to this
|
|
/// declaration, which will either be the declaration itself (if it's
|
|
/// also a declaration context) or its declaration context.
|
|
DeclContext *getInnermostDeclContext() const;
|
|
|
|
/// Retrieve the module in which this declaration resides.
|
|
LLVM_READONLY
|
|
ModuleDecl *getModuleContext() const;
|
|
|
|
/// getASTContext - Return the ASTContext that this decl lives in.
|
|
LLVM_READONLY
|
|
ASTContext &getASTContext() const {
|
|
if (auto dc = Context.dyn_cast<DeclContext *>())
|
|
return dc->getASTContext();
|
|
|
|
return *Context.get<ASTContext *>();
|
|
}
|
|
|
|
const DeclAttributes &getAttrs() const {
|
|
return Attrs;
|
|
}
|
|
|
|
DeclAttributes &getAttrs() {
|
|
return Attrs;
|
|
}
|
|
|
|
/// Returns the starting location of the entire declaration.
|
|
SourceLoc getStartLoc() const { return getSourceRange().Start; }
|
|
|
|
/// Returns the end location of the entire declaration.
|
|
SourceLoc getEndLoc() const { return getSourceRange().End; }
|
|
|
|
/// Returns the preferred location when referring to declarations
|
|
/// in diagnostics.
|
|
SourceLoc getLoc(bool SerializedOK = true) const;
|
|
|
|
/// Returns the source range of the entire declaration.
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Returns the source range of the declaration including its attributes.
|
|
SourceRange getSourceRangeIncludingAttrs() const;
|
|
|
|
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;
|
|
|
|
/// 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;
|
|
|
|
/// Pretty-print the given declaration.
|
|
///
|
|
/// \param Printer ASTPrinter object.
|
|
///
|
|
/// \param Opts Options to control how pretty-printing is performed.
|
|
///
|
|
/// \returns true if the declaration was printed or false if the print options
|
|
/// required the declaration to be skipped from printing.
|
|
bool print(ASTPrinter &Printer, const PrintOptions &Opts) const;
|
|
|
|
/// Determine whether this declaration should be printed when
|
|
/// encountered in its declaration context's list of members.
|
|
bool shouldPrintInContext(const PrintOptions &PO) const;
|
|
|
|
bool walk(ASTWalker &walker);
|
|
|
|
/// Return whether this declaration has been determined invalid.
|
|
bool isInvalid() const { return Bits.Decl.Invalid; }
|
|
|
|
/// Mark this declaration invalid.
|
|
void setInvalid(bool isInvalid = true) { Bits.Decl.Invalid = isInvalid; }
|
|
|
|
/// Determine whether this declaration was implicitly generated by the
|
|
/// compiler (rather than explicitly written in source code).
|
|
bool isImplicit() const { return Bits.Decl.Implicit; }
|
|
|
|
/// Mark this declaration as implicit.
|
|
void setImplicit(bool implicit = true) { Bits.Decl.Implicit = implicit; }
|
|
|
|
/// Get the validation state.
|
|
ValidationState getValidationState() const {
|
|
return ValidationState(Bits.Decl.ValidationState);
|
|
}
|
|
|
|
private:
|
|
friend class DeclValidationRAII;
|
|
|
|
/// Set the validation state.
|
|
void setValidationState(ValidationState VS) {
|
|
assert(VS > getValidationState() && "Validation is unidirectional");
|
|
Bits.Decl.ValidationState = unsigned(VS);
|
|
}
|
|
|
|
public:
|
|
/// Whether the declaration is in the middle of validation or not.
|
|
bool isBeingValidated() const {
|
|
switch (getValidationState()) {
|
|
case ValidationState::Unchecked:
|
|
case ValidationState::Checked:
|
|
return false;
|
|
case ValidationState::Checking:
|
|
return true;
|
|
}
|
|
llvm_unreachable("Unknown ValidationState");
|
|
}
|
|
|
|
bool hasValidationStarted() const {
|
|
return getValidationState() > ValidationState::Unchecked;
|
|
}
|
|
|
|
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;
|
|
|
|
/// Returns true if there is a Clang AST node associated
|
|
/// with self.
|
|
bool hasClangNode() const {
|
|
return Bits.Decl.FromClang;
|
|
}
|
|
|
|
/// Retrieve the Clang AST node from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
ClangNode getClangNode() const {
|
|
if (!Bits.Decl.FromClang)
|
|
return ClangNode();
|
|
|
|
return getClangNodeImpl();
|
|
}
|
|
|
|
/// Retrieve the Clang declaration from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
const clang::Decl *getClangDecl() const {
|
|
if (!Bits.Decl.FromClang)
|
|
return nullptr;
|
|
|
|
return getClangNodeImpl().getAsDecl();
|
|
}
|
|
|
|
/// Retrieve the Clang macro from which this declaration was
|
|
/// synthesized, if any.
|
|
LLVM_READONLY
|
|
const clang::MacroInfo *getClangMacro() {
|
|
if (!Bits.Decl.FromClang)
|
|
return nullptr;
|
|
|
|
return getClangNodeImpl().getAsMacro();
|
|
}
|
|
|
|
/// Return the GenericContext if the Decl has one.
|
|
LLVM_READONLY
|
|
const GenericContext *getAsGenericContext() const;
|
|
|
|
bool isPrivateStdlibDecl(bool treatNonBuiltinProtocolsAsPublic = true) const;
|
|
|
|
AvailabilityContext getAvailabilityForLinkage() const;
|
|
|
|
/// Whether this declaration or one of its outer contexts has the
|
|
/// @_weakLinked attribute.
|
|
bool isAlwaysWeakImported() const;
|
|
|
|
/// Whether this declaration is weak-imported from the given module,
|
|
/// either because of the presence of the @_weakLinked attribute, or
|
|
/// because of availability.
|
|
///
|
|
/// Note that \p fromModule should either be the "main module" or
|
|
/// nullptr. (This is because when it is non-null, we query the
|
|
/// current deployment target, and not the deployment target that
|
|
/// the module was built with.)
|
|
///
|
|
/// If \p fromModule is the main module, this returns false when the
|
|
/// declaration is part of the main module, or if the declaration is
|
|
/// at least as available as the current deployment target.
|
|
///
|
|
/// If \p fromModule is null, we instead return true if the
|
|
/// declaration is meant to be weak linked with _some_ deployment
|
|
/// target; that is, the presence of the @_weakLinked attribute or
|
|
/// any kind of availability is enough, irrespective of the current
|
|
/// deployment target.
|
|
bool isWeakImported(ModuleDecl *fromModule) const;
|
|
|
|
/// Returns true if the nature of this declaration allows overrides.
|
|
/// Note that this does not consider whether it is final or whether
|
|
/// the class it's on is final.
|
|
///
|
|
/// If this returns true, the decl can be safely casted to ValueDecl.
|
|
bool isPotentiallyOverridable() const;
|
|
|
|
/// Emit a diagnostic tied to this declaration.
|
|
template<typename ...ArgTypes>
|
|
InFlightDiagnostic diagnose(
|
|
Diag<ArgTypes...> ID,
|
|
typename detail::PassArgument<ArgTypes>::type... Args) const {
|
|
return getDiags().diagnose(this, ID, std::move(Args)...);
|
|
}
|
|
|
|
/// Retrieve the diagnostic engine for diagnostics emission.
|
|
LLVM_READONLY
|
|
DiagnosticEngine &getDiags() const;
|
|
|
|
// Make vanilla new/delete illegal for Decls.
|
|
void *operator new(size_t Bytes) = delete;
|
|
void operator delete(void *Data) SWIFT_DELETE_OPERATOR_DELETED;
|
|
|
|
// Only allow allocation of Decls using the allocator in ASTContext
|
|
// or by doing a placement new.
|
|
void *operator new(size_t Bytes, const ASTContext &C,
|
|
unsigned Alignment = alignof(Decl));
|
|
void *operator new(size_t Bytes, void *Mem) {
|
|
assert(Mem);
|
|
return Mem;
|
|
}
|
|
};
|
|
|
|
/// Use RAII to track Decl validation progress and non-reentrancy.
|
|
class DeclValidationRAII {
|
|
Decl *D;
|
|
|
|
public:
|
|
DeclValidationRAII(const DeclValidationRAII &) = delete;
|
|
DeclValidationRAII(DeclValidationRAII &&) = delete;
|
|
void operator =(const DeclValidationRAII &) = delete;
|
|
void operator =(DeclValidationRAII &&) = delete;
|
|
|
|
DeclValidationRAII(Decl *decl) : D(decl) {
|
|
D->setValidationState(Decl::ValidationState::Checking);
|
|
}
|
|
|
|
~DeclValidationRAII() {
|
|
D->setValidationState(Decl::ValidationState::Checked);
|
|
}
|
|
};
|
|
|
|
/// 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.
|
|
};
|
|
|
|
/// 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:
|
|
/// 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 };
|
|
}
|
|
|
|
/// 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 };
|
|
}
|
|
|
|
/// 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};
|
|
}
|
|
|
|
/// Determine the kind of requirement
|
|
RequirementReprKind getKind() const { return Kind; }
|
|
|
|
/// Determine whether this requirement is invalid.
|
|
bool isInvalid() const { return Invalid; }
|
|
|
|
/// Mark this requirement invalid.
|
|
void setInvalid() { Invalid = true; }
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Retrieve the location of the ':' or '==' in an explicitly-written
|
|
/// conformance or same-type requirement respectively.
|
|
SourceLoc getSeparatorLoc() const {
|
|
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);
|
|
}
|
|
|
|
/// Retrieve the first or subject type representation from the \c repr,
|
|
/// or \c nullptr if \c repr is null.
|
|
static TypeRepr *getFirstTypeRepr(const RequirementRepr *repr) {
|
|
if (!repr) return nullptr;
|
|
return repr->FirstType.getTypeRepr();
|
|
}
|
|
|
|
/// Retrieve the second or constraint type representation from the \c repr,
|
|
/// or \c nullptr if \c repr is null.
|
|
static TypeRepr *getSecondTypeRepr(const RequirementRepr *repr) {
|
|
if (!repr) return nullptr;
|
|
assert(repr->getKind() == RequirementReprKind::TypeConstraint ||
|
|
repr->getKind() == RequirementReprKind::SameType);
|
|
return repr->SecondType.getTypeRepr();
|
|
}
|
|
|
|
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(); }
|
|
|
|
/// Retrieve the location of the 'where' keyword, or an invalid
|
|
/// location if 'where' was not present.
|
|
SourceLoc getWhereLoc() const { return WhereLoc; }
|
|
|
|
/// 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; }
|
|
|
|
/// 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);
|
|
|
|
/// Retrieve the outer generic parameter list.
|
|
///
|
|
/// This is used for extensions of nested types, and in SIL mode, where a
|
|
/// single lexical context can have multiple logical generic parameter
|
|
/// lists.
|
|
GenericParamList *getOuterParameters() const { return OuterParameters; }
|
|
|
|
/// 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);
|
|
}
|
|
|
|
/// Configure the depth of the generic parameters in this list.
|
|
void setDepth(unsigned 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) const;
|
|
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 alignas(8) _GenericContext {
|
|
// Not really public. See GenericContext.
|
|
public:
|
|
llvm::PointerIntPair<GenericParamList *, 1, bool> GenericParamsAndBit;
|
|
|
|
/// The trailing where clause.
|
|
///
|
|
/// Note that this is not currently serialized, because semantic analysis
|
|
/// moves the trailing where clause into the generic parameter list.
|
|
TrailingWhereClause *TrailingWhere = nullptr;
|
|
|
|
/// The generic signature of this declaration.
|
|
llvm::PointerIntPair<GenericSignature, 1, bool> GenericSigAndBit;
|
|
};
|
|
|
|
class GenericContext : private _GenericContext, public DeclContext {
|
|
friend class GenericParamListRequest;
|
|
friend class GenericSignatureRequest;
|
|
|
|
protected:
|
|
GenericContext(DeclContextKind Kind, DeclContext *Parent,
|
|
GenericParamList *Params);
|
|
|
|
public:
|
|
/// Retrieve the set of parameters to a generic context, or null if
|
|
/// this context is not generic.
|
|
GenericParamList *getGenericParams() const;
|
|
|
|
/// Determine whether this context has generic parameters
|
|
/// of its own.
|
|
///
|
|
/// \code
|
|
/// class C<T> {
|
|
/// func f1() {} // isGeneric == false
|
|
/// func f2<T>() {} // isGeneric == true
|
|
/// }
|
|
///
|
|
/// protocol P { // isGeneric == true due to implicit Self param
|
|
/// func p() // isGeneric == false
|
|
/// }
|
|
/// \endcode
|
|
bool isGeneric() const { return getGenericParams() != nullptr; }
|
|
bool hasComputedGenericSignature() const;
|
|
bool isComputingGenericSignature() const;
|
|
|
|
/// Retrieve the trailing where clause for this extension, if any.
|
|
TrailingWhereClause *getTrailingWhereClause() const {
|
|
return TrailingWhere;
|
|
}
|
|
|
|
/// Set the trailing where clause for this extension.
|
|
void setTrailingWhereClause(TrailingWhereClause *trailingWhereClause) {
|
|
TrailingWhere = trailingWhereClause;
|
|
}
|
|
|
|
/// Retrieve the generic signature for this context.
|
|
GenericSignature getGenericSignature() const;
|
|
|
|
/// Retrieve the generic context for this context.
|
|
GenericEnvironment *getGenericEnvironment() const;
|
|
|
|
/// Retrieve the innermost generic parameter types.
|
|
TypeArrayView<GenericTypeParamType> getInnermostGenericParamTypes() const;
|
|
|
|
/// Retrieve the generic requirements.
|
|
ArrayRef<Requirement> getGenericRequirements() const;
|
|
|
|
/// Set the generic signature of this context.
|
|
void setGenericSignature(GenericSignature genericSig);
|
|
|
|
/// Retrieve the position of any where clause for this context's
|
|
/// generic parameters.
|
|
SourceRange getGenericTrailingWhereClauseSourceRange() const;
|
|
};
|
|
static_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;
|
|
friend class Decl;
|
|
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>(),
|
|
static_cast<size_t>(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 getLocFromSource() 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.
|
|
TypeRepr *ExtendedTypeRepr;
|
|
|
|
/// The nominal type being extended.
|
|
///
|
|
/// The bit indicates whether binding has been attempted. The pointer can be
|
|
/// null if either no binding was attempted or if binding could not find the
|
|
/// extended nominal.
|
|
llvm::PointerIntPair<NominalTypeDecl *, 1, bool> ExtendedNominal;
|
|
|
|
MutableArrayRef<TypeLoc> Inherited;
|
|
|
|
/// The next extension in the linked list of extensions.
|
|
///
|
|
/// The bit indicates whether this extension has been resolved to refer to
|
|
/// a known nominal type.
|
|
llvm::PointerIntPair<ExtensionDecl *, 1, bool> NextExtension
|
|
= {nullptr, false};
|
|
|
|
/// Note that we have added a member into the iterable declaration context.
|
|
void addedMember(Decl *member);
|
|
|
|
friend class ExtensionIterator;
|
|
friend class NominalTypeDecl;
|
|
friend class MemberLookupTable;
|
|
friend class ConformanceLookupTable;
|
|
friend class IterableDeclContext;
|
|
|
|
ExtensionDecl(SourceLoc extensionLoc, TypeRepr *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();
|
|
|
|
friend class ExtendedNominalRequest;
|
|
friend class Decl;
|
|
public:
|
|
using Decl::getASTContext;
|
|
|
|
/// Create a new extension declaration.
|
|
static ExtensionDecl *create(ASTContext &ctx, SourceLoc extensionLoc,
|
|
TypeRepr *extendedType,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause,
|
|
ClangNode clangNode = ClangNode());
|
|
|
|
SourceLoc getStartLoc() const { return ExtensionLoc; }
|
|
SourceLoc getLocFromSource() const { return ExtensionLoc; }
|
|
SourceRange getSourceRange() const {
|
|
return { ExtensionLoc, Braces.End };
|
|
}
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
bool hasBeenBound() const { return ExtendedNominal.getInt(); }
|
|
|
|
void setExtendedNominal(NominalTypeDecl *n) {
|
|
ExtendedNominal.setPointerAndInt(n, true);
|
|
}
|
|
|
|
/// Retrieve the type being extended.
|
|
///
|
|
/// Only use this entry point when the complete type, as spelled in the source,
|
|
/// is required. For most clients, \c getExtendedNominal(), which provides
|
|
/// only the \c NominalTypeDecl, will suffice.
|
|
Type getExtendedType() const;
|
|
|
|
/// Retrieve the nominal type declaration that is being extended.
|
|
/// Will trip an assertion if the declaration has not already been computed.
|
|
/// In order to fail fast when type checking work is attempted
|
|
/// before extension binding has taken place.
|
|
|
|
NominalTypeDecl *getExtendedNominal() const;
|
|
|
|
/// Compute the nominal type declaration that is being extended.
|
|
NominalTypeDecl *computeExtendedNominal() const;
|
|
|
|
/// \c hasBeenBound means nothing if this extension can never been bound
|
|
/// because it is not at the top level.
|
|
bool canNeverBeBound() const;
|
|
|
|
bool hasValidParent() const;
|
|
|
|
/// Determine whether this extension has already been bound to a nominal
|
|
/// type declaration.
|
|
bool alreadyBoundToNominal() const { return NextExtension.getInt(); }
|
|
|
|
/// Retrieve the extended type definition as written in the source, if it exists.
|
|
TypeRepr *getExtendedTypeRepr() const { return ExtendedTypeRepr; }
|
|
|
|
/// 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; }
|
|
|
|
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->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
return C->getIterableContextKind()
|
|
== IterableDeclContextKind::ExtensionDecl;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
};
|
|
|
|
/// Iterator that walks the extensions of a particular type.
|
|
class ExtensionIterator {
|
|
ExtensionDecl *current;
|
|
|
|
public:
|
|
ExtensionIterator() : current() { }
|
|
explicit ExtensionIterator(ExtensionDecl *current) : current(current) { }
|
|
|
|
ExtensionDecl *operator*() const { return current; }
|
|
ExtensionDecl *operator->() const { return current; }
|
|
|
|
ExtensionIterator &operator++() {
|
|
current = current->NextExtension.getPointer();
|
|
return *this;
|
|
}
|
|
|
|
ExtensionIterator operator++(int) {
|
|
ExtensionIterator tmp = *this;
|
|
++(*this);
|
|
return tmp;
|
|
}
|
|
|
|
friend bool operator==(ExtensionIterator x, ExtensionIterator y) {
|
|
return x.current == y.current;
|
|
}
|
|
|
|
friend bool operator!=(ExtensionIterator x, ExtensionIterator y) {
|
|
return x.current != y.current;
|
|
}
|
|
};
|
|
|
|
/// Range that covers a set of extensions.
|
|
class ExtensionRange {
|
|
ExtensionIterator first;
|
|
ExtensionIterator last;
|
|
|
|
public:
|
|
|
|
ExtensionRange(ExtensionIterator first, ExtensionIterator last)
|
|
: first(first), last(last) { }
|
|
|
|
typedef ExtensionIterator iterator;
|
|
iterator begin() const { return first; }
|
|
iterator end() const { return last; }
|
|
};
|
|
|
|
|
|
/// This represents one entry in a PatternBindingDecl, which are pairs of
|
|
/// Pattern and Initialization expression. The pattern is always present, but
|
|
/// the initializer can be null if there is none.
|
|
class PatternBindingEntry {
|
|
enum class Flags {
|
|
Checked = 1 << 0,
|
|
Removed = 1 << 1,
|
|
/// Whether the contents of this initializer were subsumed by
|
|
/// some other initialization, e.g., a lazy property's initializer
|
|
/// gets subsumed by the getter body.
|
|
Subsumed = 1 << 2,
|
|
};
|
|
llvm::PointerIntPair<Pattern *, 3, OptionSet<Flags>> PatternAndFlags;
|
|
|
|
struct InitializerAndEqualLoc {
|
|
// When the initializer is removed we don't actually clear the pointers
|
|
// because we might need to get initializer's source range. Since the
|
|
// initializer is ASTContext-allocated it is safe.
|
|
|
|
/// Exactly the expr the programmer wrote
|
|
Expr *originalInit;
|
|
/// Might be transformed, e.g. for a property wrapper. In the absence of
|
|
/// transformation or synthesis, holds the expr as parsed.
|
|
Expr *initAfterSynthesis;
|
|
/// The location of the equal '=' token.
|
|
SourceLoc EqualLoc;
|
|
};
|
|
|
|
union {
|
|
/// The initializer expression and its '=' token loc.
|
|
InitializerAndEqualLoc InitExpr;
|
|
|
|
/// The text of the initializer expression if deserialized from a module.
|
|
StringRef InitStringRepresentation;
|
|
};
|
|
|
|
enum class PatternFlags {
|
|
IsText = 1 << 0,
|
|
IsFullyValidated = 1 << 1,
|
|
};
|
|
/// The initializer context used for this pattern binding entry.
|
|
llvm::PointerIntPair<DeclContext *, 2, OptionSet<PatternFlags>>
|
|
InitContextAndFlags;
|
|
|
|
/// Values captured by this initializer.
|
|
CaptureInfo Captures;
|
|
|
|
friend class Parser;
|
|
friend class PatternBindingInitializer;
|
|
friend class PatternBindingDecl;
|
|
friend class ast_scope::AbstractPatternEntryScope;
|
|
friend class ast_scope::PatternEntryDeclScope;
|
|
friend class ast_scope::PatternEntryInitializerScope;
|
|
|
|
private:
|
|
// FIXME: This API is transitional. Once the callers of
|
|
// typeCheckPatternBinding are requestified, merge this bit with
|
|
// Flags::Checked.
|
|
friend class PatternBindingEntryRequest;
|
|
|
|
bool isFullyValidated() const {
|
|
return InitContextAndFlags.getInt().contains(
|
|
PatternFlags::IsFullyValidated);
|
|
}
|
|
void setFullyValidated() {
|
|
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
|
|
PatternFlags::IsFullyValidated);
|
|
}
|
|
|
|
public:
|
|
/// \p E is the initializer as parsed.
|
|
PatternBindingEntry(Pattern *P, SourceLoc EqualLoc, Expr *E,
|
|
DeclContext *InitContext)
|
|
: PatternAndFlags(P, {}), InitExpr({E, E, EqualLoc}),
|
|
InitContextAndFlags({InitContext, None}) {}
|
|
|
|
private:
|
|
Pattern *getPattern() const { return PatternAndFlags.getPointer(); }
|
|
void setPattern(Pattern *P) { PatternAndFlags.setPointer(P); }
|
|
|
|
/// Whether the given pattern binding entry is initialized.
|
|
bool isInitialized() const;
|
|
|
|
Expr *getInit() const {
|
|
if (PatternAndFlags.getInt().contains(Flags::Removed) ||
|
|
InitContextAndFlags.getInt().contains(PatternFlags::IsText))
|
|
return nullptr;
|
|
return InitExpr.initAfterSynthesis;
|
|
}
|
|
/// Retrieve the initializer if it should be executed to initialize this
|
|
/// particular pattern binding.
|
|
Expr *getExecutableInit() const {
|
|
return isInitializerSubsumed() ? nullptr : getInit();
|
|
}
|
|
SourceRange getOriginalInitRange() const;
|
|
void setInit(Expr *E);
|
|
|
|
/// Gets the text of the initializer expression, stripping out inactive
|
|
/// branches of any #ifs inside the expression.
|
|
StringRef getInitStringRepresentation(SmallVectorImpl<char> &scratch) const;
|
|
|
|
/// Sets the initializer string representation to the string that was
|
|
/// deserialized from a partial module.
|
|
void setInitStringRepresentation(StringRef str) {
|
|
InitStringRepresentation = str;
|
|
InitContextAndFlags.setInt(InitContextAndFlags.getInt() |
|
|
PatternFlags::IsText);
|
|
}
|
|
|
|
/// Whether this pattern entry can generate a string representation of its
|
|
/// initializer expression.
|
|
bool hasInitStringRepresentation() const;
|
|
|
|
/// Retrieve the location of the equal '=' token.
|
|
SourceLoc getEqualLoc() const {
|
|
return InitContextAndFlags.getInt().contains(PatternFlags::IsText)
|
|
? SourceLoc()
|
|
: InitExpr.EqualLoc;
|
|
}
|
|
|
|
/// Set the location of the equal '=' token.
|
|
void setEqualLoc(SourceLoc equalLoc) {
|
|
assert(!InitContextAndFlags.getInt().contains(PatternFlags::IsText) &&
|
|
"cannot set equal loc for textual initializer");
|
|
InitExpr.EqualLoc = equalLoc;
|
|
}
|
|
|
|
/// Retrieve the initializer after the =, if any, as it was written in the
|
|
/// source.
|
|
Expr *getOriginalInit() const;
|
|
|
|
/// Set the initializer after the = as it was written in the source.
|
|
void setOriginalInit(Expr *);
|
|
|
|
bool isInitializerChecked() const {
|
|
return PatternAndFlags.getInt().contains(Flags::Checked);
|
|
}
|
|
void setInitializerChecked() {
|
|
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Checked);
|
|
}
|
|
|
|
bool isInitializerSubsumed() const {
|
|
return PatternAndFlags.getInt().contains(Flags::Subsumed);
|
|
}
|
|
void setInitializerSubsumed() {
|
|
PatternAndFlags.setInt(PatternAndFlags.getInt() | Flags::Subsumed);
|
|
}
|
|
|
|
// Return the first variable initialized by this pattern.
|
|
VarDecl *getAnchoringVarDecl() const;
|
|
|
|
// Retrieve the declaration context for the initializer.
|
|
DeclContext *getInitContext() const {
|
|
return InitContextAndFlags.getPointer();
|
|
}
|
|
|
|
/// Override the initializer context.
|
|
void setInitContext(DeclContext *dc) { InitContextAndFlags.setPointer(dc); }
|
|
|
|
SourceLoc getStartLoc() const;
|
|
|
|
/// Retrieve the end location covered by this pattern binding entry.
|
|
///
|
|
/// \param omitAccessors Whether the computation should omit the accessors
|
|
/// from the source range.
|
|
SourceLoc getEndLoc(bool omitAccessors = false) const;
|
|
|
|
/// Retrieve the source range covered by this pattern binding entry.
|
|
///
|
|
/// \param omitAccessors Whether the computation should omit the accessors
|
|
/// from the source range.
|
|
SourceRange getSourceRange(bool omitAccessors = false) const;
|
|
|
|
CaptureInfo getCaptureInfo() const { return Captures; }
|
|
void setCaptureInfo(CaptureInfo captures) { Captures = captures; }
|
|
|
|
unsigned getNumBoundVariables() const;
|
|
|
|
private:
|
|
SourceLoc getLastAccessorEndLoc() const;
|
|
};
|
|
|
|
/// This decl contains a pattern and optional initializer for a set
|
|
/// of one or more VarDecls declared together.
|
|
///
|
|
/// For example, in
|
|
/// \code
|
|
/// var (a, b) = foo(), (c,d) = bar()
|
|
/// \endcode
|
|
///
|
|
/// this includes two entries in the pattern list. The first contains the
|
|
/// pattern "(a, b)" and the initializer "foo()". The second contains the
|
|
/// pattern "(c, d)" and the initializer "bar()".
|
|
///
|
|
class PatternBindingDecl final : public Decl,
|
|
private llvm::TrailingObjects<PatternBindingDecl, PatternBindingEntry> {
|
|
friend TrailingObjects;
|
|
friend class Decl;
|
|
friend class PatternBindingEntryRequest;
|
|
|
|
SourceLoc StaticLoc; ///< Location of the 'static/class' keyword, if present.
|
|
SourceLoc VarLoc; ///< Location of the 'var' keyword.
|
|
|
|
friend class Decl;
|
|
|
|
PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc, unsigned NumPatternEntries,
|
|
DeclContext *Parent);
|
|
SourceLoc getLocFromSource() const { return VarLoc; }
|
|
public:
|
|
static PatternBindingDecl *create(ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
ArrayRef<PatternBindingEntry> PatternList,
|
|
DeclContext *Parent);
|
|
|
|
static PatternBindingDecl *create(ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc, Pattern *Pat,
|
|
SourceLoc EqualLoc, Expr *E,
|
|
DeclContext *Parent);
|
|
|
|
static PatternBindingDecl *createImplicit(ASTContext &Ctx,
|
|
StaticSpellingKind StaticSpelling,
|
|
Pattern *Pat, Expr *E,
|
|
DeclContext *Parent,
|
|
SourceLoc VarLoc = SourceLoc());
|
|
|
|
static PatternBindingDecl *createDeserialized(
|
|
ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
unsigned NumPatternEntries,
|
|
DeclContext *Parent);
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() ? StaticLoc : VarLoc;
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
unsigned getNumPatternEntries() const {
|
|
return Bits.PatternBindingDecl.NumPatternEntries;
|
|
}
|
|
|
|
ArrayRef<PatternBindingEntry> getPatternList() const {
|
|
return const_cast<PatternBindingDecl*>(this)->getMutablePatternList();
|
|
}
|
|
|
|
void setInitStringRepresentation(unsigned i, StringRef str) {
|
|
getMutablePatternList()[i].setInitStringRepresentation(str);
|
|
}
|
|
|
|
/// Whether the given pattern entry is initialized.
|
|
bool isInitialized(unsigned i) const {
|
|
return getPatternList()[i].isInitialized();
|
|
}
|
|
|
|
Expr *getInit(unsigned i) const {
|
|
return getPatternList()[i].getInit();
|
|
}
|
|
Expr *getExecutableInit(unsigned i) const {
|
|
return getPatternList()[i].getExecutableInit();
|
|
}
|
|
Expr *getOriginalInit(unsigned i) const {
|
|
return getPatternList()[i].getOriginalInit();
|
|
}
|
|
|
|
SourceRange getOriginalInitRange(unsigned i) const {
|
|
return getPatternList()[i].getOriginalInitRange();
|
|
}
|
|
|
|
void setInit(unsigned i, Expr *E) {
|
|
getMutablePatternList()[i].setInit(E);
|
|
}
|
|
|
|
Pattern *getPattern(unsigned i) const {
|
|
return getPatternList()[i].getPattern();
|
|
}
|
|
|
|
void setPattern(unsigned i, Pattern *Pat, DeclContext *InitContext);
|
|
|
|
DeclContext *getInitContext(unsigned i) const {
|
|
return getPatternList()[i].getInitContext();
|
|
}
|
|
|
|
CaptureInfo getCaptureInfo(unsigned i) const {
|
|
return getPatternList()[i].getCaptureInfo();
|
|
}
|
|
|
|
void setCaptureInfo(unsigned i, CaptureInfo captures) {
|
|
getMutablePatternList()[i].setCaptureInfo(captures);
|
|
}
|
|
|
|
/// Given that this PBD is the parent pattern for the specified VarDecl,
|
|
/// return the entry of the VarDecl in our PatternList. For example, in:
|
|
///
|
|
/// let (a,b) = foo(), (c,d) = bar()
|
|
///
|
|
/// "a" and "b" will have index 0, since they correspond to the first pattern,
|
|
/// and "c" and "d" will have index 1 since they correspond to the second one.
|
|
unsigned getPatternEntryIndexForVarDecl(const VarDecl *VD) const;
|
|
|
|
bool isInitializerChecked(unsigned i) const {
|
|
return getPatternList()[i].isInitializerChecked();
|
|
}
|
|
|
|
void setInitializerChecked(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerChecked();
|
|
}
|
|
|
|
bool isInitializerSubsumed(unsigned i) const {
|
|
return getPatternList()[i].isInitializerSubsumed();
|
|
}
|
|
|
|
void setInitializerSubsumed(unsigned i) {
|
|
getMutablePatternList()[i].setInitializerSubsumed();
|
|
}
|
|
|
|
/// Does this binding declare something that requires storage?
|
|
bool hasStorage() const;
|
|
|
|
/// Determines whether this binding either has an initializer expression, or is
|
|
/// default initialized, without performing any type checking on it.
|
|
bool isDefaultInitializable() const {
|
|
for (unsigned i : range(getNumPatternEntries()))
|
|
if (!isDefaultInitializable(i))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Can the pattern at index i be default initialized?
|
|
bool isDefaultInitializable(unsigned i) const;
|
|
|
|
/// Does this pattern have a user-provided initializer expression?
|
|
bool isExplicitlyInitialized(unsigned i) const;
|
|
|
|
/// Whether the pattern entry at the given index can generate a string
|
|
/// representation of its initializer expression.
|
|
bool hasInitStringRepresentation(unsigned i) const {
|
|
return getPatternList()[i].hasInitStringRepresentation();
|
|
}
|
|
|
|
SourceLoc getEqualLoc(unsigned i) const;
|
|
|
|
/// When the pattern binding contains only a single variable with no
|
|
/// destructuring, retrieve that variable.
|
|
VarDecl *getSingleVar() const;
|
|
|
|
/// Return the first variable initialized by the pattern at the given index.
|
|
VarDecl *getAnchoringVarDecl(unsigned i) const;
|
|
|
|
bool isStatic() const { return Bits.PatternBindingDecl.IsStatic; }
|
|
void setStatic(bool s) { Bits.PatternBindingDecl.IsStatic = s; }
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(
|
|
Bits.PatternBindingDecl.StaticSpelling);
|
|
}
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
|
|
/// Is the pattern binding entry for this variable currently being computed?
|
|
bool isComputingPatternBindingEntry(const VarDecl *vd) const;
|
|
|
|
/// Gets the text of the initializer expression for the pattern entry at the
|
|
/// given index, stripping out inactive branches of any #ifs inside the
|
|
/// expression.
|
|
StringRef getInitStringRepresentation(unsigned i,
|
|
SmallVectorImpl<char> &scratch) const {
|
|
return getPatternList()[i].getInitStringRepresentation(scratch);
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PatternBinding;
|
|
}
|
|
|
|
private:
|
|
MutableArrayRef<PatternBindingEntry> getMutablePatternList() {
|
|
// Pattern entries are tail allocated.
|
|
return {getTrailingObjects<PatternBindingEntry>(), getNumPatternEntries()};
|
|
}
|
|
};
|
|
|
|
/// TopLevelCodeDecl - This decl is used as a container for top-level
|
|
/// expressions and statements in the main module. It is always a direct
|
|
/// child of a SourceFile. The primary reason for building these is to give
|
|
/// top-level statements a DeclContext which is distinct from the file itself.
|
|
/// This, among other things, makes it easier to distinguish between local
|
|
/// top-level variables (which are not live past the end of the statement) and
|
|
/// global variables.
|
|
class TopLevelCodeDecl : public DeclContext, public Decl {
|
|
BraceStmt *Body;
|
|
SourceLoc getLocFromSource() const { return getStartLoc(); }
|
|
friend class Decl;
|
|
public:
|
|
TopLevelCodeDecl(DeclContext *Parent, BraceStmt *Body = nullptr)
|
|
: DeclContext(DeclContextKind::TopLevelCodeDecl, Parent),
|
|
Decl(DeclKind::TopLevelCode, Parent),
|
|
Body(Body) {}
|
|
|
|
BraceStmt *getBody() const { return Body; }
|
|
void setBody(BraceStmt *b) { Body = b; }
|
|
|
|
SourceLoc getStartLoc() const;
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::TopLevelCode;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
};
|
|
|
|
/// 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;
|
|
SourceLoc getLocFromSource() const { return Clauses[0].Loc; }
|
|
friend class Decl;
|
|
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; }
|
|
|
|
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;
|
|
SourceLoc getLocFromSource() const { return StartLoc; }
|
|
friend class Decl;
|
|
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; };
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange(StartLoc, EndLoc);
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PoundDiagnostic;
|
|
}
|
|
};
|
|
|
|
class OpaqueTypeDecl;
|
|
|
|
/// ValueDecl - All named decls that are values in the language. These can
|
|
/// have a type, etc.
|
|
class ValueDecl : public Decl {
|
|
DeclName Name;
|
|
SourceLoc NameLoc;
|
|
llvm::PointerIntPair<Type, 3, OptionalEnum<AccessLevel>> TypeAndAccess;
|
|
unsigned LocalDiscriminator = 0;
|
|
|
|
struct {
|
|
/// Whether the "IsObjC" bit has been computed yet.
|
|
unsigned isObjCComputed : 1;
|
|
|
|
/// Whether this declaration is exposed to Objective-C.
|
|
unsigned isObjC : 1;
|
|
|
|
/// Whether the "overridden" declarations have been computed already.
|
|
unsigned hasOverriddenComputed : 1;
|
|
|
|
/// Whether there are any "overridden" declarations. The actual overridden
|
|
/// declarations are kept in a side table in the ASTContext.
|
|
unsigned hasOverridden : 1;
|
|
|
|
/// Whether the "isDynamic" bit has been computed yet.
|
|
unsigned isDynamicComputed : 1;
|
|
|
|
/// Whether this declaration is 'dynamic', meaning that all uses of
|
|
/// the declaration will go through an extra level of indirection that
|
|
/// allows the entity to be replaced at runtime.
|
|
unsigned isDynamic : 1;
|
|
|
|
/// Whether the "isFinal" bit has been computed yet.
|
|
unsigned isFinalComputed : 1;
|
|
|
|
/// Whether this declaration is 'final'. A final class can't be subclassed,
|
|
/// a final class member can't be overriden.
|
|
unsigned isFinal : 1;
|
|
|
|
/// Whether the "isIUO" bit" has been computed yet.
|
|
unsigned isIUOComputed : 1;
|
|
|
|
/// Whether this declaration produces an implicitly unwrapped
|
|
/// optional result.
|
|
unsigned isIUO : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
friend class OverriddenDeclsRequest;
|
|
friend class IsObjCRequest;
|
|
friend class IsFinalRequest;
|
|
friend class IsDynamicRequest;
|
|
friend class IsImplicitlyUnwrappedOptionalRequest;
|
|
friend class InterfaceTypeRequest;
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
protected:
|
|
ValueDecl(DeclKind K,
|
|
llvm::PointerUnion<DeclContext *, ASTContext *> context,
|
|
DeclName name, SourceLoc NameLoc)
|
|
: Decl(K, context), Name(name), NameLoc(NameLoc) {
|
|
Bits.ValueDecl.AlreadyInLookupTable = false;
|
|
Bits.ValueDecl.CheckedRedeclaration = false;
|
|
Bits.ValueDecl.IsUserAccessible = true;
|
|
}
|
|
|
|
// 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:
|
|
/// 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(
|
|
bool skipIsObjCResolution = false) const;
|
|
|
|
/// Determine whether the given declaration can infer @objc, or the
|
|
/// Objective-C name, if used to satisfy the given requirement.
|
|
bool canInferObjCFromRequirement(ValueDecl *requirement);
|
|
|
|
SourceLoc getNameLoc() const { return NameLoc; }
|
|
|
|
bool isUsableFromInline() const;
|
|
|
|
/// Returns \c true if this declaration is *not* intended to be used directly
|
|
/// by application developers despite the visibility.
|
|
bool shouldHideFromEditor() const;
|
|
|
|
bool hasAccess() const {
|
|
return TypeAndAccess.getInt().hasValue();
|
|
}
|
|
|
|
/// Access control is done by Requests.
|
|
friend class AccessLevelRequest;
|
|
|
|
/// Returns the access level specified explicitly by the user, or provided by
|
|
/// default according to language rules.
|
|
///
|
|
/// Most of the time this is not the interesting value to check; access is
|
|
/// limited by enclosing scopes per SE-0025. Use #getFormalAccessScope to
|
|
/// check if access control is being used consistently, and to take features
|
|
/// such as \c \@testable and \c \@usableFromInline into account.
|
|
///
|
|
/// \sa getFormalAccessScope
|
|
/// \sa hasOpenAccess
|
|
AccessLevel getFormalAccess() const;
|
|
|
|
/// Determine whether this Decl has either Private or FilePrivate access,
|
|
/// and its DeclContext does not.
|
|
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
|
|
/// \sa hasOpenAccess
|
|
AccessScope
|
|
getFormalAccessScope(const DeclContext *useDC = nullptr,
|
|
bool treatUsableFromInlineAsPublic = false) const;
|
|
|
|
|
|
/// Copy the formal access level and @usableFromInline attribute from
|
|
/// \p source.
|
|
///
|
|
/// If \p sourceIsParentContext is true, an access level of \c private will
|
|
/// be copied as \c fileprivate, to ensure that this declaration will be
|
|
/// available everywhere \p source is.
|
|
void copyFormalAccessFrom(const ValueDecl *source,
|
|
bool sourceIsParentContext = false);
|
|
|
|
/// Returns the access level that actually controls how a declaration should
|
|
/// be emitted and may be used.
|
|
///
|
|
/// This is the access used when making optimization and code generation
|
|
/// decisions. It should not be used at the AST or semantic level.
|
|
AccessLevel getEffectiveAccess() const;
|
|
|
|
void setAccess(AccessLevel access) {
|
|
assert(!hasAccess() && "access already set");
|
|
overwriteAccess(access);
|
|
}
|
|
|
|
/// Overwrite the access of this declaration.
|
|
///
|
|
/// This is needed in the LLDB REPL.
|
|
void overwriteAccess(AccessLevel access) {
|
|
TypeAndAccess.setInt(access);
|
|
}
|
|
|
|
/// Returns true if this declaration is accessible from the given context.
|
|
///
|
|
/// A private declaration is accessible from any DeclContext within the same
|
|
/// source file.
|
|
///
|
|
/// An internal declaration is accessible from any DeclContext within the same
|
|
/// module.
|
|
///
|
|
/// A public declaration is accessible everywhere.
|
|
///
|
|
/// If \p DC is null, returns true only if this declaration is public.
|
|
///
|
|
/// If \p forConformance is true, we ignore the visibility of the protocol
|
|
/// when evaluating protocol extension members. This language rule allows a
|
|
/// protocol extension of a private protocol to provide default
|
|
/// implementations for the requirements of a public protocol, even when
|
|
/// the default implementations are not visible to name lookup.
|
|
bool isAccessibleFrom(const DeclContext *DC,
|
|
bool forConformance = false) const;
|
|
|
|
/// Returns whether this declaration should be treated as \c open from
|
|
/// \p useDC. This is very similar to #getFormalAccess, but takes
|
|
/// \c \@testable into account.
|
|
///
|
|
/// This is mostly only useful when considering requirements on an override:
|
|
/// if the base declaration is \c open, the override might have to be too.
|
|
bool hasOpenAccess(const DeclContext *useDC) const;
|
|
|
|
/// FIXME: This is deprecated.
|
|
bool isRecursiveValidation() const;
|
|
|
|
/// Retrieve the "interface" type of this value, which uses
|
|
/// GenericTypeParamType if the declaration is generic. For a generic
|
|
/// function, this will have a GenericFunctionType with a
|
|
/// GenericSignature inside the type.
|
|
Type getInterfaceType() const;
|
|
bool hasInterfaceType() const;
|
|
|
|
/// Set the interface type for the given value.
|
|
void setInterfaceType(Type type);
|
|
|
|
/// isInstanceMember - Determine whether this value is an instance member
|
|
/// of an enum or protocol.
|
|
bool isInstanceMember() const;
|
|
|
|
/// Retrieve the context discriminator for this local value, which
|
|
/// is the index of this declaration in the sequence of
|
|
/// discriminated declarations with the same name in the current
|
|
/// context. Only local functions and variables with getters and
|
|
/// setters have discriminators.
|
|
unsigned getLocalDiscriminator() const;
|
|
void setLocalDiscriminator(unsigned index);
|
|
|
|
/// Retrieve the declaration that this declaration overrides, if any.
|
|
ValueDecl *getOverriddenDecl() const;
|
|
|
|
/// Retrieve the declarations that this declaration overrides, if any.
|
|
llvm::TinyPtrVector<ValueDecl *> getOverriddenDecls() const;
|
|
|
|
/// Set the declaration that this declaration overrides.
|
|
void setOverriddenDecl(ValueDecl *overridden) {
|
|
setOverriddenDecls(overridden);
|
|
}
|
|
|
|
/// Set the declarations that this declaration overrides.
|
|
void setOverriddenDecls(ArrayRef<ValueDecl *> overridden);
|
|
|
|
/// Whether the overridden declarations have already been computed.
|
|
bool overriddenDeclsComputed() const;
|
|
|
|
/// Compute the untyped overload signature for this declaration.
|
|
OverloadSignature getOverloadSignature() const;
|
|
|
|
/// Retrieve the type used to describe this entity for the purposes of
|
|
/// overload resolution.
|
|
CanType getOverloadSignatureType() const;
|
|
|
|
/// Returns true if the decl requires Objective-C interop.
|
|
///
|
|
/// This can be true even if there is no 'objc' attribute on the declaration.
|
|
/// In that case it was inferred by the type checker and set with a call to
|
|
/// markAsObjC().
|
|
bool isObjC() const;
|
|
|
|
/// Note whether this declaration is known to be exposed to Objective-C.
|
|
void setIsObjC(bool Value);
|
|
|
|
/// Is this declaration 'final'?
|
|
bool isFinal() const;
|
|
|
|
/// Is this declaration marked with 'dynamic'?
|
|
bool isDynamic() const;
|
|
|
|
bool isObjCDynamic() const {
|
|
return isObjC() && isDynamic();
|
|
}
|
|
|
|
bool isNativeDynamic() const {
|
|
return !isObjC() && isDynamic();
|
|
}
|
|
|
|
/// Set whether this type is 'dynamic' or not.
|
|
void setIsDynamic(bool value);
|
|
|
|
/// Whether the 'dynamic' bit has been computed already.
|
|
bool isDynamicComputed() const {
|
|
return LazySemanticInfo.isDynamicComputed;
|
|
}
|
|
|
|
/// Returns true if this decl can be found by id-style dynamic lookup.
|
|
bool canBeAccessedByDynamicLookup() const;
|
|
|
|
/// Returns true if this declaration has an implicitly unwrapped optional
|
|
/// result. The precise meaning depends on the declaration kind:
|
|
/// - for properties, the value is IUO
|
|
/// - for subscripts, the element type is IUO
|
|
/// - for functions, the result type is IUO
|
|
/// - for constructors, the failability kind is IUO
|
|
bool isImplicitlyUnwrappedOptional() const;
|
|
|
|
/// Should only be set on imported and deserialized declarations; parsed
|
|
/// declarations compute this lazily via a request.
|
|
void setImplicitlyUnwrappedOptional(bool isIUO) {
|
|
LazySemanticInfo.isIUOComputed = 1;
|
|
LazySemanticInfo.isIUO = isIUO;
|
|
}
|
|
|
|
/// Returns the protocol requirements that this decl conforms to.
|
|
ArrayRef<ValueDecl *>
|
|
getSatisfiedProtocolRequirements(bool Sorted = false) const;
|
|
|
|
/// Determines the kind of access that should be performed by a
|
|
/// DeclRefExpr or MemberRefExpr use of this value in the specified
|
|
/// context.
|
|
///
|
|
/// \param DC The declaration context.
|
|
///
|
|
/// \param isAccessOnSelf Whether this is a member access on the implicit
|
|
/// 'self' declaration of the declaration context.
|
|
AccessSemantics getAccessSemanticsFromContext(const DeclContext *DC,
|
|
bool isAccessOnSelf) const;
|
|
|
|
/// 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;
|
|
|
|
/// Returns true if the declaration's interface type is a function type with a
|
|
/// curried self parameter.
|
|
bool hasCurriedSelf() const;
|
|
|
|
/// Returns true if the declaration has a parameter list associated with it.
|
|
///
|
|
/// Note that not all declarations with function interface types have
|
|
/// parameter lists, for example an enum element without associated values.
|
|
bool hasParameterList() const;
|
|
|
|
/// Returns the number of curry levels in the declaration's interface type.
|
|
unsigned getNumCurryLevels() const;
|
|
|
|
/// Get the decl for this value's opaque result type, if it has one.
|
|
OpaqueTypeDecl *getOpaqueResultTypeDecl() const;
|
|
|
|
/// Get the representative for this value's opaque result type, if it has one.
|
|
OpaqueReturnTypeRepr *getOpaqueResultTypeRepr() const;
|
|
|
|
/// Retrieve the attribute associating this declaration with a
|
|
/// function builder, if there is one.
|
|
CustomAttr *getAttachedFunctionBuilder() const;
|
|
|
|
/// Retrieve the @functionBuilder type attached to this declaration,
|
|
/// if there is one.
|
|
Type getFunctionBuilderType() 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;
|
|
|
|
/// 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; }
|
|
|
|
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->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_GenericTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_GenericTypeDecl;
|
|
}
|
|
};
|
|
|
|
/// OpaqueTypeDecl - This is a declaration of an opaque type. The opaque type
|
|
/// is formally equivalent to its underlying type, but abstracts it away from
|
|
/// clients of the opaque type, only exposing the type as something conforming
|
|
/// to a given set of constraints.
|
|
///
|
|
/// Currently, opaque types do not normally have an explicit spelling in source
|
|
/// code. One is formed implicitly when a declaration is written with an opaque
|
|
/// result type, as in:
|
|
///
|
|
/// func foo() -> opaque SignedInteger { return 1 }
|
|
///
|
|
/// The declared type is a special kind of ArchetypeType representing the
|
|
/// abstracted underlying type.
|
|
class OpaqueTypeDecl : public GenericTypeDecl {
|
|
/// The original declaration that "names" the opaque type. Although a specific
|
|
/// opaque type cannot be explicitly named, oapque types can propagate
|
|
/// arbitrarily through expressions, so we need to know *which* opaque type is
|
|
/// propagated.
|
|
ValueDecl *NamingDecl;
|
|
|
|
/// The generic signature of the opaque interface to the type. This is the
|
|
/// outer generic signature with an added generic parameter representing the
|
|
/// underlying type.
|
|
GenericSignature OpaqueInterfaceGenericSignature;
|
|
|
|
/// The generic parameter that represents the underlying type.
|
|
GenericTypeParamType *UnderlyingInterfaceType;
|
|
|
|
/// If known, the underlying type and conformances of the opaque type,
|
|
/// expressed as a SubstitutionMap for the opaque interface generic signature.
|
|
/// This maps types in the interface generic signature to the outer generic
|
|
/// signature of the original declaration.
|
|
Optional<SubstitutionMap> UnderlyingTypeSubstitutions;
|
|
|
|
mutable Identifier OpaqueReturnTypeIdentifier;
|
|
|
|
public:
|
|
OpaqueTypeDecl(ValueDecl *NamingDecl,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *DC,
|
|
GenericSignature OpaqueInterfaceGenericSignature,
|
|
GenericTypeParamType *UnderlyingInterfaceType);
|
|
|
|
ValueDecl *getNamingDecl() const { return NamingDecl; }
|
|
|
|
void setNamingDecl(ValueDecl *D) {
|
|
assert(!NamingDecl && "already have naming decl");
|
|
NamingDecl = D;
|
|
}
|
|
|
|
/// Is this opaque type the opaque return type of the given function?
|
|
///
|
|
/// This is more complex than just checking `getNamingDecl` because the
|
|
/// function could also be the getter of a storage declaration.
|
|
bool isOpaqueReturnTypeOfFunction(const AbstractFunctionDecl *func) const;
|
|
|
|
GenericSignature getOpaqueInterfaceGenericSignature() const {
|
|
return OpaqueInterfaceGenericSignature;
|
|
}
|
|
|
|
GenericTypeParamType *getUnderlyingInterfaceType() const {
|
|
return UnderlyingInterfaceType;
|
|
}
|
|
|
|
Optional<SubstitutionMap> getUnderlyingTypeSubstitutions() const {
|
|
return UnderlyingTypeSubstitutions;
|
|
}
|
|
|
|
void setUnderlyingTypeSubstitutions(SubstitutionMap subs) {
|
|
assert(!UnderlyingTypeSubstitutions.hasValue() && "resetting underlying type?!");
|
|
UnderlyingTypeSubstitutions = subs;
|
|
}
|
|
|
|
// Opaque type decls are currently always implicit
|
|
SourceRange getSourceRange() const { return SourceRange(); }
|
|
|
|
// Get the identifier string that can be used to cross-reference unnamed
|
|
// opaque return types across files.
|
|
Identifier getOpaqueReturnTypeIdentifier() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::OpaqueType;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::OpaqueType;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// TypeAliasDecl - This is a declaration of a typealias, for example:
|
|
///
|
|
/// typealias Foo = Int
|
|
///
|
|
/// TypeAliasDecl's always have 'MetatypeType' type.
|
|
///
|
|
class TypeAliasDecl : public GenericTypeDecl {
|
|
friend class UnderlyingTypeRequest;
|
|
|
|
/// The location of the 'typealias' keyword
|
|
SourceLoc TypeAliasLoc;
|
|
|
|
/// The location of the equal '=' token
|
|
SourceLoc EqualLoc;
|
|
|
|
/// The end of the type, valid even when the type cannot be parsed
|
|
SourceLoc TypeEndLoc;
|
|
|
|
/// The location of the right-hand side of the typealias binding
|
|
TypeLoc UnderlyingTy;
|
|
|
|
public:
|
|
TypeAliasDecl(SourceLoc TypeAliasLoc, SourceLoc EqualLoc, Identifier Name,
|
|
SourceLoc NameLoc, GenericParamList *GenericParams,
|
|
DeclContext *DC);
|
|
|
|
SourceLoc getStartLoc() const { return TypeAliasLoc; }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Returns the location of the equal '=' token
|
|
SourceLoc getEqualLoc() const {
|
|
return EqualLoc;
|
|
}
|
|
|
|
void setTypeEndLoc(SourceLoc e) { TypeEndLoc = e; }
|
|
|
|
/// Retrieve the TypeRepr corresponding to the parsed underlying type.
|
|
TypeRepr *getUnderlyingTypeRepr() const {
|
|
return UnderlyingTy.getTypeRepr();
|
|
}
|
|
void setUnderlyingTypeRepr(TypeRepr *repr) {
|
|
UnderlyingTy = repr;
|
|
}
|
|
|
|
/// Retrieve the interface type of the underlying type.
|
|
Type getUnderlyingType() const;
|
|
void setUnderlyingType(Type type);
|
|
|
|
/// For generic typealiases, return the unbound generic type.
|
|
UnboundGenericType *getUnboundGenericType() const;
|
|
|
|
/// Retrieve a sugared interface type containing the structure of the interface
|
|
/// type before any semantic validation has occured.
|
|
Type getStructuralType() 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->getAsDecl())
|
|
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
|
|
class AssociatedTypeDecl : public AbstractTypeParamDecl {
|
|
/// The location of the initial keyword.
|
|
SourceLoc KeywordLoc;
|
|
|
|
/// The default definition.
|
|
TypeRepr *DefaultDefinition;
|
|
|
|
/// The where clause attached to the associated type.
|
|
TrailingWhereClause *TrailingWhere;
|
|
|
|
LazyMemberLoader *Resolver = nullptr;
|
|
uint64_t ResolverContextData;
|
|
|
|
friend class DefaultDefinitionTypeRequest;
|
|
|
|
public:
|
|
AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name,
|
|
SourceLoc nameLoc, TypeRepr *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());
|
|
}
|
|
|
|
/// Check if we have a default definition type.
|
|
bool hasDefaultDefinitionType() const {
|
|
// If we have a TypeRepr, return true immediately without kicking off
|
|
// a request.
|
|
return DefaultDefinition || getDefaultDefinitionType();
|
|
}
|
|
|
|
/// Retrieve the default definition type.
|
|
Type getDefaultDefinitionType() const;
|
|
|
|
/// Retrieve the default definition as written in the source.
|
|
TypeRepr *getDefaultDefinitionTypeRepr() const {
|
|
return DefaultDefinition;
|
|
}
|
|
|
|
/// Retrieve the trailing where clause for this associated type, if any.
|
|
TrailingWhereClause *getTrailingWhereClause() const { return TrailingWhere; }
|
|
|
|
/// Set the trailing where clause for this associated type.
|
|
void setTrailingWhereClause(TrailingWhereClause *trailingWhereClause) {
|
|
TrailingWhere = trailingWhereClause;
|
|
}
|
|
|
|
/// Retrieve the associated type "anchor", which is the associated type
|
|
/// declaration that will be used to describe this associated type in the
|
|
/// ABI.
|
|
///
|
|
/// The associated type "anchor" is an associated type that does not
|
|
/// override any other associated type. There may be several such associated
|
|
/// types; select one deterministically.
|
|
AssociatedTypeDecl *getAssociatedTypeAnchor() const;
|
|
|
|
/// Retrieve the (first) overridden associated type declaration, if any.
|
|
AssociatedTypeDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AssociatedTypeDecl>(
|
|
AbstractTypeParamDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Retrieve the set of associated types overridden by this associated
|
|
/// type.
|
|
llvm::TinyPtrVector<AssociatedTypeDecl *> getOverriddenDecls() const;
|
|
|
|
SourceLoc getStartLoc() const { return KeywordLoc; }
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::AssociatedType;
|
|
}
|
|
};
|
|
|
|
class MemberLookupTable;
|
|
class ConformanceLookupTable;
|
|
|
|
// Kinds of pointer types.
|
|
enum PointerTypeKind : unsigned {
|
|
PTK_UnsafeMutableRawPointer,
|
|
PTK_UnsafeRawPointer,
|
|
PTK_UnsafeMutablePointer,
|
|
PTK_UnsafePointer,
|
|
PTK_AutoreleasingUnsafeMutablePointer,
|
|
};
|
|
|
|
static inline bool isRawPointerKind(PointerTypeKind PTK) {
|
|
switch (PTK) {
|
|
case PTK_UnsafeMutableRawPointer:
|
|
case PTK_UnsafeRawPointer:
|
|
return true;
|
|
case PTK_UnsafeMutablePointer:
|
|
case PTK_UnsafePointer:
|
|
case PTK_AutoreleasingUnsafeMutablePointer:
|
|
return false;
|
|
}
|
|
|
|
llvm_unreachable("Unhandled PointerTypeKind in switch.");
|
|
}
|
|
|
|
// Kinds of buffer pointer types.
|
|
enum BufferPointerTypeKind : unsigned {
|
|
BPTK_UnsafeMutableRawBufferPointer,
|
|
BPTK_UnsafeRawBufferPointer,
|
|
BPTK_UnsafeMutableBufferPointer,
|
|
BPTK_UnsafeBufferPointer,
|
|
};
|
|
|
|
enum KeyPathTypeKind : unsigned char {
|
|
KPTK_AnyKeyPath,
|
|
KPTK_PartialKeyPath,
|
|
KPTK_KeyPath,
|
|
KPTK_WritableKeyPath,
|
|
KPTK_ReferenceWritableKeyPath
|
|
};
|
|
|
|
/// NominalTypeDecl - a declaration of a nominal type, like a struct.
|
|
class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
|
|
SourceRange Braces;
|
|
|
|
/// The first extension of this type.
|
|
ExtensionDecl *FirstExtension = nullptr;
|
|
|
|
/// The last extension of this type, used solely for efficient
|
|
/// insertion of new extensions.
|
|
ExtensionDecl *LastExtension = nullptr;
|
|
|
|
/// The generation at which we last loaded extensions.
|
|
unsigned ExtensionGeneration;
|
|
|
|
/// Prepare to traverse the list of extensions.
|
|
void prepareExtensions();
|
|
|
|
/// Retrieve the conformance loader (if any), and removing it in the
|
|
/// same operation. The caller is responsible for loading the
|
|
/// conformances.
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoader() {
|
|
if (!Bits.NominalTypeDecl.HasLazyConformances)
|
|
return { nullptr, 0 };
|
|
|
|
return takeConformanceLoaderSlow();
|
|
}
|
|
|
|
/// Slow path for \c takeConformanceLoader().
|
|
std::pair<LazyMemberLoader *, uint64_t> takeConformanceLoaderSlow();
|
|
|
|
/// A lookup table containing all of the members of this type and
|
|
/// its extensions.
|
|
///
|
|
/// 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; it should be manipulated through \c isLookupTablePopulated()
|
|
/// and \c setLookupTablePopulated().
|
|
llvm::PointerIntPair<MemberLookupTable *, 1, bool> LookupTable;
|
|
|
|
/// Prepare the lookup table to make it ready for lookups.
|
|
void prepareLookupTable();
|
|
|
|
/// True if the entries in \c LookupTable are complete--that is, if a
|
|
/// name is present, it contains all members with that name.
|
|
bool isLookupTablePopulated() const;
|
|
void setLookupTablePopulated(bool value);
|
|
|
|
/// Note that we have added a member into the iterable declaration context,
|
|
/// so that it can also be added to the lookup table (if needed).
|
|
void addedMember(Decl *member);
|
|
|
|
/// Note that we have added an extension into the nominal type,
|
|
/// so that its members can eventually be added to the lookup table.
|
|
void addedExtension(ExtensionDecl *ext);
|
|
|
|
/// A lookup table used to find the protocol conformances of
|
|
/// a given nominal type.
|
|
mutable ConformanceLookupTable *ConformanceTable = nullptr;
|
|
|
|
/// Prepare the conformance table.
|
|
void prepareConformanceTable() const;
|
|
|
|
/// Returns the protocol requirements that \c Member conforms to.
|
|
ArrayRef<ValueDecl *>
|
|
getSatisfiedProtocolRequirementsForMember(const ValueDecl *Member,
|
|
bool Sorted) const;
|
|
|
|
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 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)
|
|
{
|
|
Bits.NominalTypeDecl.AddedImplicitInitializers = false;
|
|
ExtensionGeneration = 0;
|
|
Bits.NominalTypeDecl.HasLazyConformances = false;
|
|
}
|
|
|
|
friend class ProtocolType;
|
|
|
|
public:
|
|
using GenericTypeDecl::getASTContext;
|
|
|
|
SourceRange getBraces() const { return Braces; }
|
|
|
|
void setBraces(SourceRange braces) { Braces = braces; }
|
|
|
|
/// 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;
|
|
|
|
/// Do we need to use resilient access patterns outside of this type's
|
|
/// resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// getDeclaredType - Retrieve the type declared by this entity, without
|
|
/// any generic parameters bound if this is a generic type.
|
|
Type getDeclaredType() const;
|
|
|
|
/// getDeclaredInterfaceType - Retrieve the type declared by this entity, with
|
|
/// generic parameters bound if this is a generic type.
|
|
Type getDeclaredInterfaceType() const;
|
|
|
|
/// Add a new extension to this nominal type.
|
|
void addExtension(ExtensionDecl *extension);
|
|
|
|
/// Retrieve the set of extensions of this type.
|
|
ExtensionRange getExtensions();
|
|
|
|
/// Special-behaviour flags passed to lookupDirect()
|
|
enum class LookupDirectFlags {
|
|
/// Whether to include @_implements members.
|
|
/// Used by conformance-checking to find special @_implements members.
|
|
IncludeAttrImplements = 1 << 0,
|
|
};
|
|
|
|
/// Find all of the declarations with the given name within this nominal type
|
|
/// and its extensions.
|
|
///
|
|
/// This routine does not look into superclasses, nor does it consider
|
|
/// protocols to which the nominal type conforms. Furthermore, the resulting
|
|
/// set of declarations has not been filtered for visibility, nor have
|
|
/// overridden declarations been removed.
|
|
TinyPtrVector<ValueDecl *> lookupDirect(DeclName name,
|
|
OptionSet<LookupDirectFlags> flags =
|
|
OptionSet<LookupDirectFlags>());
|
|
|
|
/// 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;
|
|
|
|
/// Is this a key path type?
|
|
Optional<KeyPathTypeKind> getKeyPathTypeKind() const;
|
|
|
|
/// Retrieve information about this type as a property wrapper.
|
|
PropertyWrapperTypeInfo getPropertyWrapperTypeInfo() const;
|
|
|
|
/// Return a collection of the stored member variables of this type.
|
|
ArrayRef<VarDecl *> getStoredProperties() const;
|
|
|
|
/// Return a collection of the stored member variables of this type, along
|
|
/// with placeholders for unimportable stored properties.
|
|
ArrayRef<Decl *> getStoredPropertiesAndMissingMemberPlaceholders() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_NominalTypeDecl;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() >= DeclKind::First_NominalTypeDecl &&
|
|
D->getKind() <= DeclKind::Last_NominalTypeDecl;
|
|
}
|
|
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
return C->getIterableContextKind()
|
|
== IterableDeclContextKind::NominalTypeDecl;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) { return true; }
|
|
static bool classof(const ExtensionDecl *D) { return false; }
|
|
};
|
|
|
|
/// This is the declaration of an enum.
|
|
///
|
|
/// For example:
|
|
///
|
|
/// \code
|
|
/// enum Bool {
|
|
/// case false
|
|
/// case true
|
|
/// }
|
|
///
|
|
/// enum Optional<T> {
|
|
/// case none
|
|
/// case some(T)
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Bool" or "Optional" in the above example).
|
|
class EnumDecl final : public NominalTypeDecl {
|
|
SourceLoc EnumLoc;
|
|
|
|
enum SemanticInfoFlags : uint8_t {
|
|
// Is the raw type valid?
|
|
HasComputedRawType = 1 << 0,
|
|
// Is the complete set of (auto-incremented) raw values available?
|
|
HasFixedRawValues = 1 << 1,
|
|
// Is the complete set of raw values type checked?
|
|
HasFixedRawValuesAndTypes = 1 << 2,
|
|
};
|
|
|
|
struct {
|
|
/// The raw type and a bit to indicate whether the
|
|
/// raw was computed yet or not.
|
|
llvm::PointerIntPair<Type, 3, OptionSet<SemanticInfoFlags>> RawTypeAndFlags;
|
|
|
|
bool hasRawType() const {
|
|
return RawTypeAndFlags.getInt().contains(HasComputedRawType);
|
|
}
|
|
void cacheRawType(Type ty) {
|
|
auto flags = RawTypeAndFlags.getInt() | HasComputedRawType;
|
|
RawTypeAndFlags.setPointerAndInt(ty, flags);
|
|
}
|
|
|
|
bool hasFixedRawValues() const {
|
|
return RawTypeAndFlags.getInt().contains(HasFixedRawValues);
|
|
}
|
|
bool hasCheckedRawValues() const {
|
|
return RawTypeAndFlags.getInt().contains(HasFixedRawValuesAndTypes);
|
|
}
|
|
} LazySemanticInfo;
|
|
|
|
friend class EnumRawValuesRequest;
|
|
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);
|
|
}
|
|
|
|
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 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);
|
|
}
|
|
|
|
/// Record that this enum has had all of its raw values computed.
|
|
void setHasFixedRawValues();
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Enum;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Determine whether this enum declares a raw type in its inheritance clause.
|
|
bool hasRawType() const { return (bool)getRawType(); }
|
|
|
|
/// Retrieve the declared raw type of the enum from its inheritance clause,
|
|
/// or null if it has none.
|
|
Type getRawType() const;
|
|
|
|
/// Set the raw type of the enum from its inheritance clause.
|
|
void setRawType(Type rawType) {
|
|
auto flags = LazySemanticInfo.RawTypeAndFlags.getInt();
|
|
LazySemanticInfo.RawTypeAndFlags.setPointerAndInt(
|
|
rawType, flags | HasComputedRawType);
|
|
}
|
|
|
|
/// 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.
|
|
///
|
|
/// This is the predicate used when deciding if a switch statement needs a
|
|
/// default case. It should not be used for optimization or code generation.
|
|
///
|
|
/// \sa isEffectivelyExhaustive
|
|
bool isFormallyExhaustive(const DeclContext *useDC) const;
|
|
|
|
/// True if the enum can be exhaustively switched within a function defined
|
|
/// within \p M, with \p expansion specifying whether the function is
|
|
/// inlinable.
|
|
///
|
|
/// This is the predicate used when making optimization and code generation
|
|
/// decisions. It should not be used at the AST or semantic level.
|
|
///
|
|
/// \sa isFormallyExhaustive
|
|
bool isEffectivelyExhaustive(ModuleDecl *M,
|
|
ResilienceExpansion expansion) const;
|
|
};
|
|
|
|
/// StructDecl - This is the declaration of a struct, for example:
|
|
///
|
|
/// struct Complex { var R : Double, I : Double }
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Complex" in the above example).
|
|
class StructDecl final : public NominalTypeDecl {
|
|
SourceLoc StructLoc;
|
|
|
|
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->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Does this struct contain unreferenceable storage, such as C fields that
|
|
/// cannot be represented in Swift?
|
|
bool hasUnreferenceableStorage() const {
|
|
return Bits.StructDecl.HasUnreferenceableStorage;
|
|
}
|
|
|
|
void setHasUnreferenceableStorage(bool v) {
|
|
Bits.StructDecl.HasUnreferenceableStorage = v;
|
|
}
|
|
};
|
|
|
|
/// The kind of artificial main to generate for a class.
|
|
enum class ArtificialMainKind : uint8_t {
|
|
NSApplicationMain,
|
|
UIApplicationMain,
|
|
};
|
|
|
|
/// This is the base type for AncestryOptions. Each flag describes possible
|
|
/// interesting kinds of superclasses that a class may have.
|
|
enum class AncestryFlags : uint8_t {
|
|
/// The class or one of its superclasses is @objc.
|
|
ObjC = (1<<0),
|
|
|
|
/// The class or one of its superclasses is @objcMembers.
|
|
ObjCMembers = (1<<1),
|
|
|
|
/// The class or one of its superclasses is generic.
|
|
Generic = (1<<2),
|
|
|
|
/// The class or one of its superclasses is resilient.
|
|
Resilient = (1<<3),
|
|
|
|
/// The class or one of its superclasses has resilient metadata and is in a
|
|
/// different resilience domain.
|
|
ResilientOther = (1<<4),
|
|
|
|
/// The class or one of its superclasses is imported from Clang.
|
|
ClangImported = (1<<5),
|
|
|
|
/// The class or one of its superclasses requires stored property initializers.
|
|
RequiresStoredPropertyInits = (1<<6),
|
|
};
|
|
|
|
/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
|
|
/// kinds of superclasses that a class may have.
|
|
using AncestryOptions = OptionSet<AncestryFlags>;
|
|
|
|
/// ClassDecl - This is the declaration of a class, for example:
|
|
///
|
|
/// class Complex { var R : Double, I : Double }
|
|
///
|
|
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
|
|
/// to get the declared type ("Complex" in the above example).
|
|
class ClassDecl final : public NominalTypeDecl {
|
|
class ObjCMethodLookupTable;
|
|
|
|
SourceLoc ClassLoc;
|
|
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;
|
|
|
|
/// Create the Objective-C member lookup table.
|
|
void createObjCMethodLookup();
|
|
|
|
struct {
|
|
/// The superclass decl and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<ClassDecl *, 1, bool> SuperclassDecl;
|
|
|
|
/// The superclass type and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> SuperclassType;
|
|
} LazySemanticInfo;
|
|
|
|
bool hasForcedEmittedMembers() const {
|
|
return Bits.ClassDecl.HasForcedEmittedMembers;
|
|
}
|
|
|
|
void setHasForcedEmittedMembers() {
|
|
Bits.ClassDecl.HasForcedEmittedMembers = true;
|
|
}
|
|
|
|
friend class SuperclassDeclRequest;
|
|
friend class SuperclassTypeRequest;
|
|
friend class EmittedMembersRequest;
|
|
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 the member area of this class's metadata (which consists
|
|
/// of field offsets and vtable entries) is to be considered opaque by clients.
|
|
///
|
|
/// Note that even @_fixed_layout classes have resilient metadata if they are
|
|
/// in a resilient module.
|
|
bool hasResilientMetadata() const;
|
|
|
|
/// Determine whether this class has resilient metadata when accessed from the
|
|
/// given module and resilience expansion.
|
|
bool hasResilientMetadata(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// Determine whether this class has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }
|
|
|
|
/// Retrieve the superclass of this class, or null if there is no superclass.
|
|
Type getSuperclass() const;
|
|
|
|
/// Retrieve the ClassDecl for the superclass of this class, or null if there
|
|
/// is no superclass.
|
|
ClassDecl *getSuperclassDecl() const;
|
|
|
|
/// Check if this class is a superclass or equal to the given class.
|
|
bool isSuperclassOf(ClassDecl *other) 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);
|
|
}
|
|
|
|
/// Walk this class and all of the superclasses of this class, transitively,
|
|
/// invoking the callback function for each class.
|
|
///
|
|
/// \param fn The callback function that will be invoked for each superclass.
|
|
/// It can return \c Continue to continue the traversal. Returning
|
|
/// \c SkipChildren halts the search and returns \c false, while returning
|
|
/// \c Stop halts the search and returns \c true.
|
|
///
|
|
/// \returns \c true if \c fn returned \c Stop for any class, \c false
|
|
/// otherwise.
|
|
bool walkSuperclasses(
|
|
llvm::function_ref<TypeWalker::Action(ClassDecl *)> fn) const;
|
|
|
|
//// Whether this class requires all of its stored properties to
|
|
//// have initializers in the class definition.
|
|
bool requiresStoredPropertyInits() const {
|
|
return checkAncestry(AncestryFlags::RequiresStoredPropertyInits);
|
|
}
|
|
|
|
/// \see getForeignClassKind
|
|
enum class ForeignKind : uint8_t {
|
|
/// A normal Swift or Objective-C class.
|
|
Normal = 0,
|
|
/// An imported Core Foundation type. These are AnyObject-compatible but
|
|
/// do not have runtime metadata.
|
|
CFType,
|
|
/// An imported Objective-C type whose class and metaclass symbols are not
|
|
/// both available at link-time but can be accessed through the Objective-C
|
|
/// runtime.
|
|
RuntimeOnly
|
|
};
|
|
|
|
/// Whether this class is "foreign", meaning that it is implemented
|
|
/// by a runtime that Swift does not have first-class integration
|
|
/// with. This generally means that:
|
|
/// - class data is either abstracted or cannot be made to
|
|
/// fit with Swift's metatype schema, and/or
|
|
/// - there is no facility for subclassing or adding polymorphic
|
|
/// methods to the class.
|
|
///
|
|
/// We may find ourselves wanting to break this bit into more
|
|
/// precise chunks later.
|
|
ForeignKind getForeignClassKind() const {
|
|
return static_cast<ForeignKind>(Bits.ClassDecl.RawForeignKind);
|
|
}
|
|
void setForeignClassKind(ForeignKind kind) {
|
|
Bits.ClassDecl.RawForeignKind = static_cast<unsigned>(kind);
|
|
}
|
|
|
|
/// Returns true if this class is any kind of "foreign class".
|
|
///
|
|
/// \see getForeignClassKind
|
|
bool isForeign() const {
|
|
return getForeignClassKind() != ForeignKind::Normal;
|
|
}
|
|
|
|
/// 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.ComputedHasMissingDesignatedInitializers = 1;
|
|
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.ComputedHasMissingVTableEntries = 1;
|
|
Bits.ClassDecl.HasMissingVTableEntries = newValue;
|
|
}
|
|
|
|
/// Returns true if this class cannot be used with weak or unowned
|
|
/// references.
|
|
///
|
|
/// Note that this is true if this class or any of its ancestor classes
|
|
/// are marked incompatible.
|
|
bool isIncompatibleWithWeakReferences() const;
|
|
|
|
void setIsIncompatibleWithWeakReferences(bool newValue = true) {
|
|
Bits.ClassDecl.IsIncompatibleWithWeakReferences = newValue;
|
|
}
|
|
|
|
/// Find a method of a class that overrides a given method.
|
|
/// Return nullptr, if no such method exists.
|
|
AbstractFunctionDecl *findOverridingDecl(
|
|
const AbstractFunctionDecl *method) const;
|
|
|
|
/// Find a method implementation which will be used when a given method
|
|
/// is invoked on an instance of this class. This implementation may stem
|
|
/// either from a class itself or its direct or indirect superclasses.
|
|
AbstractFunctionDecl *findImplementingMethod(
|
|
const AbstractFunctionDecl *method) const;
|
|
|
|
/// Retrieve the destructor for this class.
|
|
DestructorDecl *getDestructor() const;
|
|
|
|
/// Determine whether this class inherits the convenience initializers
|
|
/// from its superclass.
|
|
bool inheritsSuperclassInitializers();
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Walks the class hierarchy starting from this class, checking various
|
|
/// conditions.
|
|
AncestryOptions checkAncestry() const;
|
|
|
|
/// Check if the class has ancestry of the given kind.
|
|
bool checkAncestry(AncestryFlags flag) const {
|
|
return checkAncestry().contains(flag);
|
|
}
|
|
|
|
/// The type of metaclass to use for a class.
|
|
enum class MetaclassKind : uint8_t {
|
|
ObjC,
|
|
SwiftStub,
|
|
};
|
|
|
|
/// Determine which sort of metaclass to use for this class
|
|
MetaclassKind getMetaclassKind() const;
|
|
|
|
/// Retrieve the name to use for this class when interoperating with
|
|
/// the Objective-C runtime.
|
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
|
|
|
/// 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 with the given selector.
|
|
void recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector);
|
|
|
|
/// Get all the members of this class, synthesizing any implicit members
|
|
/// that appear in the vtable if needed.
|
|
DeclRange getEmittedMembers() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Class;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
|
|
/// Returns true if the decl uses the Objective-C generics model.
|
|
///
|
|
/// This is true of imported Objective-C classes.
|
|
bool usesObjCGenericsModel() const {
|
|
return hasClangNode() && isGenericContext() && isObjC();
|
|
}
|
|
|
|
/// 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()
|
|
/// }
|
|
///
|
|
/// Every protocol has an implicitly-created 'Self' generic parameter that
|
|
/// stands for a type that conforms to the protocol. For example,
|
|
///
|
|
/// protocol Cloneable {
|
|
/// func clone() -> Self
|
|
/// }
|
|
///
|
|
class ProtocolDecl final : public NominalTypeDecl {
|
|
SourceLoc ProtocolLoc;
|
|
|
|
ArrayRef<ProtocolDecl *> InheritedProtocols;
|
|
|
|
struct {
|
|
/// The superclass decl and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<ClassDecl *, 1, bool> SuperclassDecl;
|
|
|
|
/// The superclass type and a bit to indicate whether the
|
|
/// superclass was computed yet or not.
|
|
llvm::PointerIntPair<Type, 1, bool> SuperclassType;
|
|
} LazySemanticInfo;
|
|
|
|
/// The generic signature representing exactly the new requirements introduced
|
|
/// by this protocol.
|
|
const Requirement *RequirementSignature = nullptr;
|
|
|
|
/// Returns the cached result of \c requiresClass or \c None if it hasn't yet
|
|
/// been computed.
|
|
Optional<bool> getCachedRequiresClass() const {
|
|
if (Bits.ProtocolDecl.RequiresClassValid)
|
|
return Bits.ProtocolDecl.RequiresClass;
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Caches the result of \c requiresClass
|
|
void setCachedRequiresClass(bool requiresClass) {
|
|
Bits.ProtocolDecl.RequiresClassValid = true;
|
|
Bits.ProtocolDecl.RequiresClass = requiresClass;
|
|
}
|
|
|
|
/// Returns the cached result of \c existentialConformsToSelf or \c None if it
|
|
/// hasn't yet been computed.
|
|
Optional<bool> getCachedExistentialConformsToSelf() const {
|
|
if (Bits.ProtocolDecl.ExistentialConformsToSelfValid)
|
|
return Bits.ProtocolDecl.ExistentialConformsToSelf;
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Caches the result of \c existentialConformsToSelf
|
|
void setCachedExistentialConformsToSelf(bool result) {
|
|
Bits.ProtocolDecl.ExistentialConformsToSelfValid = true;
|
|
Bits.ProtocolDecl.ExistentialConformsToSelf = result;
|
|
}
|
|
|
|
/// Returns the cached result of \c existentialTypeSupported or \c None if it
|
|
/// hasn't yet been computed.
|
|
Optional<bool> getCachedExistentialTypeSupported() {
|
|
if (Bits.ProtocolDecl.ExistentialTypeSupportedValid)
|
|
return Bits.ProtocolDecl.ExistentialTypeSupported;
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Caches the result of \c existentialTypeSupported
|
|
void setCachedExistentialTypeSupported(bool supported) {
|
|
Bits.ProtocolDecl.ExistentialTypeSupportedValid = true;
|
|
Bits.ProtocolDecl.ExistentialTypeSupported = supported;
|
|
}
|
|
|
|
ArrayRef<ProtocolDecl *> getInheritedProtocolsSlow();
|
|
|
|
bool hasLazyRequirementSignature() const {
|
|
return Bits.ProtocolDecl.HasLazyRequirementSignature;
|
|
}
|
|
|
|
friend class SuperclassDeclRequest;
|
|
friend class SuperclassTypeRequest;
|
|
friend class RequirementSignatureRequest;
|
|
friend class ProtocolRequiresClassRequest;
|
|
friend class ExistentialConformsToSelfRequest;
|
|
friend class ExistentialTypeSupportedRequest;
|
|
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.
|
|
ArrayRef<ProtocolDecl *> getInheritedProtocols() const {
|
|
if (Bits.ProtocolDecl.InheritedProtocolsValid)
|
|
return InheritedProtocols;
|
|
|
|
return const_cast<ProtocolDecl *>(this)->getInheritedProtocolsSlow();
|
|
}
|
|
|
|
/// Determine whether this protocol has a superclass.
|
|
bool hasSuperclass() const { return (bool)getSuperclassDecl(); }
|
|
|
|
/// 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;
|
|
|
|
/// Returns a protocol requirement with the given name, or nullptr if the
|
|
/// name has multiple overloads, or no overloads at all.
|
|
ValueDecl *getSingleRequirement(DeclName name) const;
|
|
|
|
/// Returns an associated type with the given name, or nullptr if one does
|
|
/// not exist.
|
|
AssociatedTypeDecl *getAssociatedType(Identifier name) const;
|
|
|
|
/// Walk this protocol and all of the protocols inherited by this protocol,
|
|
/// transitively, invoking the callback function for each protocol.
|
|
///
|
|
/// \param fn The callback function that will be invoked for each inherited
|
|
/// protocol. It can return \c Continue to continue the traversal,
|
|
/// \c SkipChildren to avoid visiting the children of the given protocol
|
|
/// but continue the search, and \c Stop to halt the search.
|
|
///
|
|
/// \returns \c true if \c fn returned \c Stop for any protocol, \c false
|
|
/// otherwise.
|
|
bool walkInheritedProtocols(
|
|
llvm::function_ref<TypeWalker::Action(ProtocolDecl *)> fn) const;
|
|
|
|
/// Determine whether this protocol inherits from the given ("super")
|
|
/// protocol.
|
|
bool inheritsFrom(const ProtocolDecl *Super) const;
|
|
|
|
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;
|
|
|
|
/// Determine whether an existential conforming to this protocol can be
|
|
/// matched with a generic type parameter constrained to this protocol.
|
|
/// This is only permitted if there is nothing "non-trivial" that we
|
|
/// can do with the metatype, which means the protocol must not have
|
|
/// any static methods and must be declared @objc.
|
|
bool existentialConformsToSelf() const;
|
|
|
|
/// Does this protocol require a self-conformance witness table?
|
|
bool requiresSelfConformanceWitnessTable() const;
|
|
|
|
/// 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() const;
|
|
|
|
private:
|
|
void computeKnownProtocolKind() const;
|
|
|
|
public:
|
|
/// If this is known to be a compiler-known protocol, returns the kind.
|
|
/// Otherwise returns None.
|
|
Optional<KnownProtocolKind> getKnownProtocolKind() const {
|
|
if (Bits.ProtocolDecl.KnownProtocol == 0)
|
|
computeKnownProtocolKind();
|
|
|
|
if (Bits.ProtocolDecl.KnownProtocol == 1)
|
|
return None;
|
|
|
|
return static_cast<KnownProtocolKind>(Bits.ProtocolDecl.KnownProtocol - 2);
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// 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 type witness for an associated type, or a null
|
|
/// type if there is no default.
|
|
Type getDefaultTypeWitness(AssociatedTypeDecl *assocType) const;
|
|
|
|
/// Set the default type witness for an associated type.
|
|
void setDefaultTypeWitness(AssociatedTypeDecl *assocType, Type witness);
|
|
|
|
/// Returns the default witness for a requirement, or nullptr if there is
|
|
/// no default.
|
|
Witness getDefaultWitness(ValueDecl *requirement) const;
|
|
|
|
/// Record the default witness for a requirement.
|
|
void setDefaultWitness(ValueDecl *requirement, Witness witness);
|
|
|
|
/// Returns the default associated conformance witness for an associated
|
|
/// type, or \c None if there is no default.
|
|
Optional<ProtocolConformanceRef> getDefaultAssociatedConformanceWitness(
|
|
CanType association,
|
|
ProtocolDecl *requirement) const;
|
|
|
|
/// Set the default associated conformance witness for the given
|
|
/// associated conformance.
|
|
void setDefaultAssociatedConformanceWitness(
|
|
CanType association,
|
|
ProtocolDecl *requirement,
|
|
ProtocolConformanceRef conformance);
|
|
|
|
/// Retrieve the name to use for this protocol when interoperating
|
|
/// with the Objective-C runtime.
|
|
StringRef getObjCRuntimeName(llvm::SmallVectorImpl<char> &buffer) const;
|
|
|
|
/// Retrieve the 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;
|
|
|
|
/// Is the requirement signature currently being computed?
|
|
bool isComputingRequirementSignature() const;
|
|
|
|
/// Has the requirement signature been computed yet?
|
|
bool isRequirementSignatureComputed() const {
|
|
return RequirementSignature != nullptr;
|
|
}
|
|
|
|
void setRequirementSignature(ArrayRef<Requirement> requirements);
|
|
|
|
void setLazyRequirementSignature(LazyMemberLoader *lazyLoader,
|
|
uint64_t requirementSignatureData);
|
|
|
|
private:
|
|
ArrayRef<Requirement> getCachedRequirementSignature() const;
|
|
|
|
public:
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const GenericTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const NominalTypeDecl *D) {
|
|
return D->getKind() == DeclKind::Protocol;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
if (auto D = C->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
static bool classof(const IterableDeclContext *C) {
|
|
auto NTD = dyn_cast<NominalTypeDecl>(C);
|
|
return NTD && classof(NTD);
|
|
}
|
|
};
|
|
|
|
/// AbstractStorageDecl - This is the common superclass for VarDecl and
|
|
/// SubscriptDecl, representing potentially settable memory locations.
|
|
class AbstractStorageDecl : public ValueDecl {
|
|
friend class SetterAccessLevelRequest;
|
|
friend class IsGetterMutatingRequest;
|
|
friend class IsSetterMutatingRequest;
|
|
friend class OpaqueReadOwnershipRequest;
|
|
friend class StorageImplInfoRequest;
|
|
friend class RequiresOpaqueAccessorsRequest;
|
|
friend class RequiresOpaqueModifyCoroutineRequest;
|
|
friend class SynthesizeAccessorRequest;
|
|
|
|
public:
|
|
static const size_t MaxNumAccessors = 255;
|
|
private:
|
|
/// A record of the accessors for the declaration.
|
|
class alignas(1 << 3) AccessorRecord final :
|
|
private llvm::TrailingObjects<AccessorRecord, AccessorDecl*> {
|
|
friend TrailingObjects;
|
|
|
|
using AccessorIndex = uint8_t;
|
|
static const AccessorIndex InvalidIndex = 0;
|
|
|
|
/// The range of the braces around the accessor clause.
|
|
SourceRange Braces;
|
|
|
|
/// The number of accessors currently stored in this record.
|
|
AccessorIndex NumAccessors;
|
|
|
|
/// The storage capacity of this record for accessors. Always includes
|
|
/// enough space for adding opaque accessors to the record, which are the
|
|
/// only accessors that should ever be added retroactively; hence this
|
|
/// field is only here for the purposes of safety checks.
|
|
AccessorIndex AccessorsCapacity;
|
|
|
|
/// Either 0, meaning there is no registered accessor of the given kind,
|
|
/// or the index+1 of the accessor in the accessors array.
|
|
AccessorIndex AccessorIndices[NumAccessorKinds];
|
|
|
|
AccessorRecord(SourceRange braces,
|
|
ArrayRef<AccessorDecl*> accessors,
|
|
AccessorIndex accessorsCapacity);
|
|
public:
|
|
static AccessorRecord *create(ASTContext &ctx, SourceRange braces,
|
|
ArrayRef<AccessorDecl*> accessors);
|
|
|
|
SourceRange getBracesRange() const { return Braces; }
|
|
|
|
inline AccessorDecl *getAccessor(AccessorKind kind) const;
|
|
|
|
ArrayRef<AccessorDecl *> getAllAccessors() const {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
void addOpaqueAccessor(AccessorDecl *accessor);
|
|
|
|
private:
|
|
MutableArrayRef<AccessorDecl *> getAccessorsBuffer() {
|
|
return { getTrailingObjects<AccessorDecl*>(), NumAccessors };
|
|
}
|
|
|
|
bool registerAccessor(AccessorDecl *accessor, AccessorIndex index);
|
|
};
|
|
|
|
llvm::PointerIntPair<AccessorRecord*, 3, OptionalEnum<AccessLevel>> Accessors;
|
|
|
|
struct {
|
|
unsigned IsGetterMutatingComputed : 1;
|
|
unsigned IsGetterMutating : 1;
|
|
unsigned IsSetterMutatingComputed : 1;
|
|
unsigned IsSetterMutating : 1;
|
|
unsigned OpaqueReadOwnershipComputed : 1;
|
|
unsigned OpaqueReadOwnership : 2;
|
|
unsigned ImplInfoComputed : 1;
|
|
unsigned RequiresOpaqueAccessorsComputed : 1;
|
|
unsigned RequiresOpaqueAccessors : 1;
|
|
unsigned RequiresOpaqueModifyCoroutineComputed : 1;
|
|
unsigned RequiresOpaqueModifyCoroutine : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
/// The implementation info for the accessors.
|
|
StorageImplInfo ImplInfo;
|
|
|
|
/// Add a synthesized accessor.
|
|
void setSynthesizedAccessor(AccessorKind kind, AccessorDecl *getter);
|
|
|
|
protected:
|
|
AbstractStorageDecl(DeclKind Kind, bool IsStatic, DeclContext *DC,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
StorageIsMutable_t supportsMutation)
|
|
: ValueDecl(Kind, DC, Name, NameLoc),
|
|
ImplInfo(StorageImplInfo::getSimpleStored(supportsMutation)) {
|
|
Bits.AbstractStorageDecl.IsStatic = IsStatic;
|
|
}
|
|
|
|
public:
|
|
|
|
/// Should this declaration be treated as if annotated with transparent
|
|
/// attribute.
|
|
bool isTransparent() const;
|
|
|
|
/// Is this a type ('static') variable?
|
|
bool isStatic() const {
|
|
return Bits.AbstractStorageDecl.IsStatic;
|
|
}
|
|
void setStatic(bool IsStatic) {
|
|
Bits.AbstractStorageDecl.IsStatic = IsStatic;
|
|
}
|
|
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
|
|
/// Return the interface type of the stored value.
|
|
Type getValueInterfaceType() const;
|
|
|
|
/// Determine how this storage is implemented.
|
|
StorageImplInfo getImplInfo() const;
|
|
|
|
/// Overwrite the registered implementation-info. This should be
|
|
/// used carefully.
|
|
void setImplInfo(StorageImplInfo implInfo) {
|
|
LazySemanticInfo.ImplInfoComputed = 1;
|
|
ImplInfo = implInfo;
|
|
}
|
|
|
|
ReadImplKind getReadImpl() const {
|
|
return getImplInfo().getReadImpl();
|
|
}
|
|
WriteImplKind getWriteImpl() const {
|
|
return getImplInfo().getWriteImpl();
|
|
}
|
|
ReadWriteImplKind getReadWriteImpl() const {
|
|
return getImplInfo().getReadWriteImpl();
|
|
}
|
|
|
|
|
|
/// Return true if this is a VarDecl that has storage associated with
|
|
/// it.
|
|
bool hasStorage() const {
|
|
return getImplInfo().hasStorage();
|
|
}
|
|
|
|
/// Return true if this storage has the basic accessors/capability
|
|
/// to be mutated. This is generally constant after the accessors are
|
|
/// installed by the parser/importer/whatever.
|
|
///
|
|
/// Note that this is different from the mutability of the declaration
|
|
/// in the user language: sometimes we can assign to declarations that
|
|
/// don't support mutation (e.g. to initialize them), and sometimes we
|
|
/// can't mutate things that do support mutation (e.g. because their
|
|
/// setter is private).
|
|
StorageIsMutable_t supportsMutation() const {
|
|
return getImplInfo().supportsMutation();
|
|
}
|
|
|
|
/// 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;
|
|
|
|
/// Does this storage declaration have explicitly-defined accessors
|
|
/// written in the source?
|
|
bool hasParsedAccessors() const;
|
|
|
|
/// Return the ownership of values opaquely read from this storage.
|
|
OpaqueReadOwnership getOpaqueReadOwnership() const;
|
|
void setOpaqueReadOwnership(OpaqueReadOwnership ownership) {
|
|
LazySemanticInfo.OpaqueReadOwnership = unsigned(ownership);
|
|
LazySemanticInfo.OpaqueReadOwnershipComputed = true;
|
|
}
|
|
|
|
/// Return true if reading this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isGetterMutating() const;
|
|
void setIsGetterMutating(bool isMutating) {
|
|
LazySemanticInfo.IsGetterMutating = isMutating;
|
|
LazySemanticInfo.IsGetterMutatingComputed = true;
|
|
}
|
|
|
|
/// Return true if modifying this storage requires the ability to
|
|
/// modify the base value.
|
|
bool isSetterMutating() const;
|
|
void setIsSetterMutating(bool isMutating) {
|
|
LazySemanticInfo.IsSetterMutating = isMutating;
|
|
LazySemanticInfo.IsSetterMutatingComputed = true;
|
|
}
|
|
|
|
AccessorDecl *getAccessor(AccessorKind kind) const {
|
|
if (auto info = Accessors.getPointer())
|
|
return info->getAccessor(kind);
|
|
return nullptr;
|
|
}
|
|
|
|
ArrayRef<AccessorDecl*> getAllAccessors() const {
|
|
if (const auto *info = Accessors.getPointer())
|
|
return info->getAllAccessors();
|
|
return {};
|
|
}
|
|
|
|
/// Return an accessor that this storage is expected to have, synthesizing
|
|
/// one if necessary. Note that will always synthesize one, even if the
|
|
/// accessor is not part of the expected opaque set for the storage, so use
|
|
/// with caution.
|
|
AccessorDecl *getSynthesizedAccessor(AccessorKind kind) const;
|
|
|
|
/// Return an accessor part of the set of opaque accessors dictated by the
|
|
/// requirements of the ABI.
|
|
///
|
|
/// This will synthesize the accessor if one is required but not specified
|
|
/// in source; for example, most of the time a mutable property is required
|
|
/// to have a 'modify' accessor, but if the property was only written with
|
|
/// 'get' and 'set' accessors, 'modify' will be synthesized to call 'get'
|
|
/// followed by 'set'.
|
|
///
|
|
/// If the accessor is not needed for ABI reasons, this returns nullptr.
|
|
/// To ensure an accessor is always returned, use getSynthesizedAccessor().
|
|
AccessorDecl *getOpaqueAccessor(AccessorKind kind) const;
|
|
|
|
/// Return an accessor that was written in source. Returns null if the
|
|
/// accessor was not explicitly defined by the user.
|
|
AccessorDecl *getParsedAccessor(AccessorKind kind) const;
|
|
|
|
/// Visit all parsed accessors.
|
|
void visitParsedAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
/// Visit all opaque accessor kinds.
|
|
void visitExpectedOpaqueAccessors(
|
|
llvm::function_ref<void (AccessorKind)>) const;
|
|
|
|
/// Visit all opaque accessors.
|
|
void visitOpaqueAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
/// Visit all eagerly emitted accessors.
|
|
///
|
|
/// This is the union of the parsed and opaque sets.
|
|
void visitEmittedAccessors(llvm::function_ref<void (AccessorDecl*)>) const;
|
|
|
|
void setAccessors(SourceLoc lbraceLoc, ArrayRef<AccessorDecl*> accessors,
|
|
SourceLoc rbraceLoc);
|
|
|
|
/// Add a setter to an existing Computed var.
|
|
///
|
|
/// This should only be used by the ClangImporter.
|
|
void setComputedSetter(AccessorDecl *Set);
|
|
|
|
/// Does this storage require opaque accessors of any kind?
|
|
bool requiresOpaqueAccessors() const;
|
|
|
|
/// Does this storage require an opaque accessor of the given kind?
|
|
bool requiresOpaqueAccessor(AccessorKind kind) const;
|
|
|
|
/// Does this storage require a 'get' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueGetter() const {
|
|
return getOpaqueReadOwnership() != OpaqueReadOwnership::Borrowed;
|
|
}
|
|
|
|
/// Does this storage require a 'read' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueReadCoroutine() const {
|
|
return getOpaqueReadOwnership() != OpaqueReadOwnership::Owned;
|
|
}
|
|
|
|
/// Does this storage require a 'set' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueSetter() const { return supportsMutation(); }
|
|
|
|
/// Does this storage require a 'modify' accessor in its opaque-accessors set?
|
|
bool requiresOpaqueModifyCoroutine() const;
|
|
|
|
SourceRange getBracesRange() const {
|
|
if (auto info = Accessors.getPointer())
|
|
return info->getBracesRange();
|
|
return SourceRange();
|
|
}
|
|
|
|
AccessLevel getSetterFormalAccess() const;
|
|
|
|
AccessScope
|
|
getSetterFormalAccessScope(const DeclContext *useDC = nullptr,
|
|
bool treatUsableFromInlineAsPublic = false) const;
|
|
|
|
void setSetterAccess(AccessLevel accessLevel) {
|
|
assert(!Accessors.getInt().hasValue());
|
|
overwriteSetterAccess(accessLevel);
|
|
}
|
|
|
|
void overwriteSetterAccess(AccessLevel accessLevel);
|
|
|
|
/// Given that this is an Objective-C property or subscript declaration,
|
|
/// produce its getter selector.
|
|
ObjCSelector
|
|
getObjCGetterSelector(Identifier preferredName = Identifier()) const;
|
|
|
|
/// Given that this is an Objective-C property or subscript declaration,
|
|
/// produce its setter selector.
|
|
ObjCSelector
|
|
getObjCSetterSelector(Identifier preferredName = Identifier()) const;
|
|
|
|
AbstractStorageDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AbstractStorageDecl>(ValueDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Returns the location of 'override' keyword, if any.
|
|
SourceLoc getOverrideLoc() const;
|
|
|
|
/// Returns true if this declaration has a setter accessible from the given
|
|
/// context.
|
|
///
|
|
/// If \p DC is null, returns true only if the setter is public.
|
|
///
|
|
/// See \c isAccessibleFrom for a discussion of the \p forConformance
|
|
/// parameter.
|
|
bool isSetterAccessibleFrom(const DeclContext *DC,
|
|
bool forConformance=false) const;
|
|
|
|
/// Determine how this storage declaration should actually be accessed.
|
|
AccessStrategy getAccessStrategy(AccessSemantics semantics,
|
|
AccessKind accessKind,
|
|
ModuleDecl *module,
|
|
ResilienceExpansion expansion) const;
|
|
|
|
/// 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;
|
|
|
|
/// Do we need to use resilient access patterns outside of this
|
|
/// property's resilience domain?
|
|
bool isResilient() const;
|
|
|
|
/// Do we need to use resilient access patterns when accessing this
|
|
/// property from the given module?
|
|
bool isResilient(ModuleDecl *M, ResilienceExpansion expansion) const;
|
|
|
|
/// True if the storage can be referenced by a keypath directly.
|
|
/// Otherwise, its override must be referenced.
|
|
bool isValidKeyPathComponent() const;
|
|
|
|
/// True if the storage exports a property descriptor for key paths in
|
|
/// other modules.
|
|
bool exportsPropertyDescriptor() const;
|
|
|
|
/// True if any of the accessors to the storage is private or fileprivate.
|
|
bool hasPrivateAccessor() const;
|
|
|
|
bool hasDidSetOrWillSetDynamicReplacement() const;
|
|
|
|
bool hasAnyNativeDynamicAccessors() const;
|
|
|
|
bool hasAnyDynamicReplacementAccessors() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_AbstractStorageDecl &&
|
|
D->getKind() <= DeclKind::Last_AbstractStorageDecl;
|
|
}
|
|
};
|
|
|
|
/// Describes which synthesized property for a property with an attached
|
|
/// wrapper is being referenced.
|
|
enum class PropertyWrapperSynthesizedPropertyKind {
|
|
/// The backing storage property, which is a stored property of the
|
|
/// wrapper type.
|
|
Backing,
|
|
/// A storage wrapper (e.g., `$foo`), which is a wrapper over the
|
|
/// wrapper instance's `projectedValue` property.
|
|
StorageWrapper,
|
|
};
|
|
|
|
/// VarDecl - 'var' and 'let' declarations.
|
|
class VarDecl : public AbstractStorageDecl {
|
|
friend class NamingPatternRequest;
|
|
NamedPattern *NamingPattern = nullptr;
|
|
|
|
public:
|
|
enum class Introducer : uint8_t {
|
|
Let = 0,
|
|
Var = 1
|
|
};
|
|
|
|
protected:
|
|
PointerUnion<PatternBindingDecl *, Stmt *, VarDecl *> Parent;
|
|
|
|
VarDecl(DeclKind kind, bool isStatic, Introducer introducer,
|
|
bool issCaptureList, SourceLoc nameLoc, Identifier name,
|
|
DeclContext *dc, StorageIsMutable_t supportsMutation);
|
|
|
|
public:
|
|
VarDecl(bool isStatic, Introducer introducer, bool isCaptureList,
|
|
SourceLoc nameLoc, Identifier name, DeclContext *dc)
|
|
: VarDecl(DeclKind::Var, isStatic, introducer, isCaptureList, nameLoc,
|
|
name, dc, StorageIsMutable_t(introducer == Introducer::Var)) {}
|
|
|
|
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() : "_";
|
|
}
|
|
|
|
/// Get the type of the variable within its context. If the context is generic,
|
|
/// this will use archetypes.
|
|
Type getType() const;
|
|
|
|
/// Retrieve the source range of the variable type, or an invalid range if the
|
|
/// variable's type is not explicitly written in the source.
|
|
///
|
|
/// Only for use in diagnostics. It is not always possible to always
|
|
/// precisely point to the variable type because of type aliases.
|
|
SourceRange getTypeSourceRangeForDiagnostics() const;
|
|
|
|
/// 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 {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<PatternBindingDecl *>();
|
|
}
|
|
void setParentPatternBinding(PatternBindingDecl *PBD) {
|
|
assert(PBD);
|
|
Parent = PBD;
|
|
}
|
|
|
|
/// Return the Pattern involved in initializing this VarDecl. However, recall
|
|
/// that the Pattern may be involved in initializing more than just this one
|
|
/// vardecl. For example, if this is a VarDecl for "x", the pattern may be
|
|
/// "(x, y)" and the initializer on the PatternBindingDecl may be "(1,2)" or
|
|
/// "foo()".
|
|
///
|
|
/// If this has no parent pattern binding decl or statement associated, it
|
|
/// returns null.
|
|
///
|
|
Pattern *getParentPattern() const;
|
|
|
|
/// Returns the parsed type of this variable declaration. For parameters, this
|
|
/// is the parsed type the user explicitly wrote. For variables, this is the
|
|
/// type the user wrote in the typed pattern that binds this variable.
|
|
///
|
|
/// Note that there are many cases where the user may elide types. This will
|
|
/// return null in those cases.
|
|
TypeRepr *getTypeReprOrParentPatternTypeRepr() const;
|
|
|
|
/// Return the statement that owns the pattern associated with this VarDecl,
|
|
/// if one exists.
|
|
///
|
|
/// NOTE: After parsing and before type checking, all VarDecls from
|
|
/// CaseLabelItem's Patterns return their CaseStmt. After type checking, we
|
|
/// will have constructed the CaseLabelItem VarDecl linked list implying this
|
|
/// will return nullptr. After type checking, if one wishes to find a parent
|
|
/// pattern of a VarDecl of a CaseStmt, \see getRecursiveParentPatternStmt
|
|
/// instead.
|
|
Stmt *getParentPatternStmt() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<Stmt *>();
|
|
}
|
|
|
|
void setParentPatternStmt(Stmt *s) {
|
|
assert(s);
|
|
Parent = s;
|
|
}
|
|
|
|
/// Look for the parent pattern stmt of this var decl, recursively
|
|
/// looking through var decl pointers and then through any
|
|
/// fallthroughts.
|
|
Stmt *getRecursiveParentPatternStmt() const;
|
|
|
|
/// Returns the var decl that this var decl is an implicit reference to if
|
|
/// such a var decl exists.
|
|
VarDecl *getParentVarDecl() const {
|
|
if (!Parent)
|
|
return nullptr;
|
|
return Parent.dyn_cast<VarDecl *>();
|
|
}
|
|
|
|
/// Set \p v to be the pattern produced VarDecl that is the parent of this
|
|
/// var decl.
|
|
void setParentVarDecl(VarDecl *v) {
|
|
assert(v && v != this);
|
|
Parent = v;
|
|
}
|
|
|
|
NamedPattern *getNamingPattern() const;
|
|
void setNamingPattern(NamedPattern *Pat);
|
|
|
|
/// If this is a VarDecl that does not belong to a CaseLabelItem's pattern,
|
|
/// return this. Otherwise, this VarDecl must belong to a CaseStmt's
|
|
/// CaseLabelItem. In that case, return the first case label item of the first
|
|
/// case stmt in a sequence of case stmts that fallthrough into each other.
|
|
///
|
|
/// NOTE: During type checking, we emit an error if we have a single case
|
|
/// label item with a pattern that has multiple var decls of the same
|
|
/// name. This means that during type checking and before type checking, we
|
|
/// may have a _malformed_ switch stmt var decl linked list since var decls in
|
|
/// the same case label item that have the same name will point at the same
|
|
/// canonical var decl, namely the first var decl with the name in the
|
|
/// canonical case label item's var decl list. This is ok, since we are going
|
|
/// to emit the error, but it requires us to be more careful/cautious before
|
|
/// type checking has been complete when relying on canonical var decls
|
|
/// matching up.
|
|
VarDecl *getCanonicalVarDecl() const;
|
|
|
|
/// If this is a case stmt var decl, return the var decl that corresponds to
|
|
/// this var decl in the first case label item of the case stmt. Returns
|
|
/// nullptr if this isn't a VarDecl that is part of a case stmt.
|
|
NullablePtr<VarDecl> getCorrespondingFirstCaseLabelItemVarDecl() const;
|
|
|
|
/// If this is a case stmt var decl, return the case body var decl that this
|
|
/// var decl maps to.
|
|
NullablePtr<VarDecl> getCorrespondingCaseBodyVariable() const;
|
|
|
|
/// Return true if this var decl is an implicit var decl belonging to a case
|
|
/// stmt's body.
|
|
bool isCaseBodyVariable() const;
|
|
|
|
/// True if the global stored property requires lazy initialization.
|
|
bool isLazilyInitializedGlobal() const;
|
|
|
|
/// Return the initializer involved in this VarDecl. Recall that the
|
|
/// initializer may be involved in initializing more than just this one
|
|
/// vardecl though. For example, if this is a VarDecl for "x", the pattern
|
|
/// may be "(x, y)" and the initializer on the PatternBindingDecl may be
|
|
/// "(1,2)" or "foo()".
|
|
///
|
|
/// If this has no parent pattern binding decl associated, or if that pattern
|
|
/// binding has no initial value, this returns null.
|
|
///
|
|
Expr *getParentInitializer() const {
|
|
if (auto *PBD = getParentPatternBinding()) {
|
|
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
|
|
return PBD->getInit(i);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/// Whether there exists an initializer for this \c VarDecl.
|
|
bool isParentInitialized() const {
|
|
if (auto *PBD = getParentPatternBinding()) {
|
|
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
|
|
return PBD->isInitialized(i);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Return whether this VarDecl has an initial value, either by checking
|
|
// if it has an initializer in its parent pattern binding or if it has
|
|
// the @_hasInitialValue attribute.
|
|
bool hasInitialValue() const {
|
|
return getAttrs().hasAttribute<HasInitialValueAttr>() ||
|
|
isParentInitialized();
|
|
}
|
|
|
|
VarDecl *getOverriddenDecl() const {
|
|
return cast_or_null<VarDecl>(AbstractStorageDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Is this an immutable 'let' property?
|
|
///
|
|
/// If this is a ParamDecl, isLet() is true iff
|
|
/// getSpecifier() == Specifier::Default.
|
|
bool isLet() const { return getIntroducer() == Introducer::Let; }
|
|
|
|
Introducer getIntroducer() const {
|
|
return Introducer(Bits.VarDecl.Introducer);
|
|
}
|
|
|
|
void setIntroducer(Introducer value) {
|
|
Bits.VarDecl.Introducer = uint8_t(value);
|
|
}
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// Determines if this var has an initializer expression that should be
|
|
/// exposed to clients.
|
|
/// There's a very narrow case when we would: if the decl is an instance
|
|
/// member with an initializer expression and the parent type is
|
|
/// @frozen and resides in a resilient module.
|
|
bool isInitExposedToClients() const;
|
|
|
|
/// Is this a special debugger variable?
|
|
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
|
void setDebuggerVar(bool IsDebuggerVar) {
|
|
Bits.VarDecl.IsDebuggerVar = IsDebuggerVar;
|
|
}
|
|
|
|
/// Is this the synthesized storage for a 'lazy' property?
|
|
bool isLazyStorageProperty() const {
|
|
return Bits.VarDecl.IsLazyStorageProperty;
|
|
}
|
|
void setLazyStorageProperty(bool IsLazyStorage) {
|
|
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
|
|
}
|
|
|
|
/// Retrieve the custom attributes that attach property wrappers to this
|
|
/// property. The returned list contains all of the attached property wrapper attributes in source order,
|
|
/// which means the outermost wrapper attribute is provided first.
|
|
llvm::TinyPtrVector<CustomAttr *> getAttachedPropertyWrappers() const;
|
|
|
|
/// Whether this property has any attached property wrappers.
|
|
bool hasAttachedPropertyWrapper() const;
|
|
|
|
/// Whether all of the attached property wrappers have an init(initialValue:) initializer.
|
|
bool allAttachedPropertyWrappersHaveInitialValueInit() const;
|
|
|
|
/// Retrieve the type of the attached property wrapper as a contextual
|
|
/// type.
|
|
///
|
|
/// \param index Which property wrapper type is being computed, where 0
|
|
/// indicates the first (outermost) attached property wrapper.
|
|
///
|
|
/// \returns a NULL type for properties without attached wrappers,
|
|
/// an error type when the property wrapper type itself is erroneous,
|
|
/// or the wrapper type itself, which may involve unbound generic
|
|
/// types.
|
|
Type getAttachedPropertyWrapperType(unsigned index) const;
|
|
|
|
/// Retrieve information about the attached property wrapper type.
|
|
///
|
|
/// \param i Which attached property wrapper type is being queried, where 0 is the outermost (first)
|
|
/// attached property wrapper type.
|
|
PropertyWrapperTypeInfo getAttachedPropertyWrapperTypeInfo(unsigned i) const;
|
|
|
|
/// Retrieve the fully resolved attached property wrapper type.
|
|
///
|
|
/// This type will be the fully-resolved form of
|
|
/// \c getAttachedPropertyWrapperType(0), which will not contain any
|
|
/// unbound generic types. It will be the type of the backing property.
|
|
Type getPropertyWrapperBackingPropertyType() const;
|
|
|
|
/// Retrieve information about the backing properties of the attached
|
|
/// property wrapper.
|
|
PropertyWrapperBackingPropertyInfo
|
|
getPropertyWrapperBackingPropertyInfo() const;
|
|
|
|
/// Retrieve information about the mutability of the composed
|
|
/// property wrappers.
|
|
Optional<PropertyWrapperMutability>
|
|
getPropertyWrapperMutability() const;
|
|
|
|
/// Retrieve the backing storage property for a property that has an
|
|
/// attached property wrapper.
|
|
///
|
|
/// The backing storage property will be a stored property of the
|
|
/// wrapper's type. This will be equivalent to
|
|
/// \c getAttachedPropertyWrapperType(0) when it is fully-specified;
|
|
/// if \c getAttachedPropertyWrapperType(0) involves an unbound
|
|
/// generic type, the backing storage property will be the appropriate
|
|
/// bound generic version.
|
|
VarDecl *getPropertyWrapperBackingProperty() const;
|
|
|
|
/// Retreive the storage wrapper for a property that has an attached
|
|
/// property wrapper.
|
|
VarDecl *getPropertyWrapperStorageWrapper() const;
|
|
|
|
/// Retrieve the backing storage property for a lazy property.
|
|
VarDecl *getLazyStorageProperty() const;
|
|
|
|
/// Whether this is a property with a property wrapper that was initialized
|
|
/// via a value of the original type, e.g.,
|
|
///
|
|
/// \code
|
|
/// @Lazy var i = 17
|
|
/// \end
|
|
bool isPropertyWrapperInitializedWithInitialValue() const;
|
|
|
|
/// Whether the memberwise initializer parameter for a property with a property wrapper type
|
|
/// uses the wrapped type.
|
|
bool isPropertyMemberwiseInitializedWithWrappedType() const;
|
|
|
|
/// If this property is the backing storage for a property with an attached
|
|
/// property wrapper, return the original property.
|
|
///
|
|
/// \param kind If not \c None, only returns the original property when
|
|
/// \c this property is the specified synthesized property.
|
|
VarDecl *getOriginalWrappedProperty(
|
|
Optional<PropertyWrapperSynthesizedPropertyKind> kind = None) const;
|
|
|
|
/// Set the property that wraps to this property as it's backing
|
|
/// property.
|
|
void setOriginalWrappedProperty(VarDecl *originalProperty);
|
|
|
|
/// Return the Objective-C runtime name for this property.
|
|
Identifier getObjCPropertyName() const;
|
|
|
|
/// Retrieve the default Objective-C selector for the getter of a
|
|
/// property of the given name.
|
|
static ObjCSelector getDefaultObjCGetterSelector(ASTContext &ctx,
|
|
Identifier propertyName);
|
|
|
|
/// Retrieve the default Objective-C selector for the setter of a
|
|
/// property of the given name.
|
|
static ObjCSelector getDefaultObjCSetterSelector(ASTContext &ctx,
|
|
Identifier propertyName);
|
|
|
|
/// If this is a simple 'let' constant, emit a note with a fixit indicating
|
|
/// that it can be rewritten to a 'var'. This is used in situations where the
|
|
/// compiler detects obvious attempts to mutate a constant.
|
|
void emitLetToVarNoteIfSimple(DeclContext *UseDC) const;
|
|
|
|
/// Returns true if the name is the self identifier and is implicit.
|
|
bool isSelfParameter() const;
|
|
|
|
/// Determine whether this property will be part of the implicit memberwise
|
|
/// initializer.
|
|
///
|
|
/// \param preferDeclaredProperties When encountering a `lazy` property
|
|
/// or a property that has an attached property wrapper, prefer the
|
|
/// actual declared property (which may or may not be considered "stored"
|
|
/// as the moment) to the backing storage property. Otherwise, the stored
|
|
/// backing property will be treated as the member-initialized property.
|
|
bool isMemberwiseInitialized(bool preferDeclaredProperties) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param;
|
|
}
|
|
};
|
|
|
|
enum class ParamSpecifier : uint8_t {
|
|
Default = 0,
|
|
InOut = 1,
|
|
Shared = 2,
|
|
Owned = 3,
|
|
};
|
|
|
|
/// A function parameter declaration.
|
|
class ParamDecl : public VarDecl {
|
|
Identifier ArgumentName;
|
|
SourceLoc ParameterNameLoc;
|
|
SourceLoc ArgumentNameLoc;
|
|
SourceLoc SpecifierLoc;
|
|
|
|
TypeRepr *TyRepr = nullptr;
|
|
|
|
struct StoredDefaultArgument {
|
|
PointerUnion<Expr *, VarDecl *> DefaultArg;
|
|
Initializer *InitContext = nullptr;
|
|
StringRef StringRepresentation;
|
|
CaptureInfo Captures;
|
|
};
|
|
|
|
enum class Flags : uint8_t {
|
|
/// Whether or not this parameter is vargs.
|
|
IsVariadic = 1 << 0,
|
|
|
|
/// Whether or not this parameter is `@autoclosure`.
|
|
IsAutoClosure = 1 << 1,
|
|
};
|
|
|
|
/// The default value, if any, along with flags.
|
|
llvm::PointerIntPair<StoredDefaultArgument *, 2, OptionSet<Flags>>
|
|
DefaultValueAndFlags;
|
|
|
|
friend class ParamSpecifierRequest;
|
|
|
|
public:
|
|
ParamDecl(SourceLoc specifierLoc, SourceLoc argumentNameLoc,
|
|
Identifier argumentName, SourceLoc parameterNameLoc,
|
|
Identifier parameterName, DeclContext *dc);
|
|
|
|
/// Create a new ParamDecl identical to the first except without the interface type.
|
|
static ParamDecl *cloneWithoutType(const ASTContext &Ctx, ParamDecl *PD);
|
|
|
|
/// Retrieve the argument (API) name for this function parameter.
|
|
Identifier getArgumentName() const { return ArgumentName; }
|
|
|
|
/// Retrieve the parameter (local) name for this function parameter.
|
|
Identifier getParameterName() const { return getName(); }
|
|
|
|
/// Retrieve the source location of the argument (API) name.
|
|
///
|
|
/// The resulting source location will be valid if the argument name
|
|
/// was specified separately from the parameter name.
|
|
SourceLoc getArgumentNameLoc() const { return ArgumentNameLoc; }
|
|
|
|
SourceLoc getParameterNameLoc() const { return ParameterNameLoc; }
|
|
|
|
SourceLoc getSpecifierLoc() const { return SpecifierLoc; }
|
|
|
|
/// Retrieve the TypeRepr corresponding to the parsed type of the parameter, if it exists.
|
|
TypeRepr *getTypeRepr() const { return TyRepr; }
|
|
void setTypeRepr(TypeRepr *repr) { TyRepr = repr; }
|
|
|
|
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 = DefaultValueAndFlags.getPointer())
|
|
return stored->DefaultArg.dyn_cast<Expr *>();
|
|
return nullptr;
|
|
}
|
|
|
|
VarDecl *getStoredProperty() const {
|
|
if (auto stored = DefaultValueAndFlags.getPointer())
|
|
return stored->DefaultArg.dyn_cast<VarDecl *>();
|
|
return nullptr;
|
|
}
|
|
|
|
void setDefaultValue(Expr *E);
|
|
|
|
void setStoredProperty(VarDecl *var);
|
|
|
|
Initializer *getDefaultArgumentInitContext() const {
|
|
if (auto stored = DefaultValueAndFlags.getPointer())
|
|
return stored->InitContext;
|
|
return nullptr;
|
|
}
|
|
|
|
void setDefaultArgumentInitContext(Initializer *initContext);
|
|
|
|
CaptureInfo getDefaultArgumentCaptureInfo() const {
|
|
assert(DefaultValueAndFlags.getPointer());
|
|
return DefaultValueAndFlags.getPointer()->Captures;
|
|
}
|
|
|
|
void setDefaultArgumentCaptureInfo(CaptureInfo captures);
|
|
|
|
/// Extracts the text of the default argument attached to the provided
|
|
/// ParamDecl, removing all inactive #if clauses and providing only the
|
|
/// text of active #if clauses.
|
|
///
|
|
/// For example, the default argument:
|
|
/// ```
|
|
/// {
|
|
/// #if false
|
|
/// print("false")
|
|
/// #else
|
|
/// print("true")
|
|
/// #endif
|
|
/// }
|
|
/// ```
|
|
/// will return
|
|
/// ```
|
|
/// {
|
|
/// print("true")
|
|
/// }
|
|
/// ```
|
|
/// \sa getDefaultValue
|
|
StringRef getDefaultValueStringRepresentation(
|
|
SmallVectorImpl<char> &scratch) const;
|
|
|
|
void setDefaultValueStringRepresentation(StringRef stringRepresentation);
|
|
|
|
/// Whether or not this parameter is varargs.
|
|
bool isVariadic() const {
|
|
return DefaultValueAndFlags.getInt().contains(Flags::IsVariadic);
|
|
}
|
|
void setVariadic(bool value = true) {
|
|
auto flags = DefaultValueAndFlags.getInt();
|
|
DefaultValueAndFlags.setInt(value ? flags | Flags::IsVariadic
|
|
: flags - Flags::IsVariadic);
|
|
}
|
|
|
|
/// Whether or not this parameter is marked with `@autoclosure`.
|
|
bool isAutoClosure() const {
|
|
return DefaultValueAndFlags.getInt().contains(Flags::IsAutoClosure);
|
|
}
|
|
void setAutoClosure(bool value = true) {
|
|
auto flags = DefaultValueAndFlags.getInt();
|
|
DefaultValueAndFlags.setInt(value ? flags | Flags::IsAutoClosure
|
|
: flags - Flags::IsAutoClosure);
|
|
}
|
|
|
|
/// Remove the type of this varargs element designator, without the array
|
|
/// type wrapping it. A parameter like "Int..." will have formal parameter
|
|
/// type of "[Int]" and this returns "Int".
|
|
static Type getVarargBaseTy(Type VarArgT);
|
|
|
|
/// Remove the type of this varargs element designator, without the array
|
|
/// type wrapping it.
|
|
Type getVarargBaseTy() const {
|
|
assert(isVariadic());
|
|
return getVarargBaseTy(getInterfaceType());
|
|
}
|
|
|
|
/// Determine whether this declaration is an anonymous closure parameter.
|
|
bool isAnonClosureParam() const;
|
|
|
|
using Specifier = ParamSpecifier;
|
|
|
|
Optional<Specifier> getCachedSpecifier() const {
|
|
if (Bits.ParamDecl.SpecifierComputed)
|
|
return Specifier(Bits.ParamDecl.Specifier);
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Return the raw specifier value for this parameter.
|
|
Specifier getSpecifier() const;
|
|
void setSpecifier(Specifier Spec);
|
|
|
|
/// Is the type of this parameter 'inout'?
|
|
bool isInOut() const { return getSpecifier() == Specifier::InOut; }
|
|
/// 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; }
|
|
|
|
bool isImmutable() const {
|
|
return isImmutableSpecifier(getSpecifier());
|
|
}
|
|
static bool isImmutableSpecifier(Specifier sp) {
|
|
switch (sp) {
|
|
case Specifier::Default:
|
|
case Specifier::Shared:
|
|
case Specifier::Owned:
|
|
return true;
|
|
case Specifier::InOut:
|
|
return false;
|
|
}
|
|
llvm_unreachable("unhandled specifier");
|
|
}
|
|
|
|
ValueOwnership getValueOwnership() const {
|
|
return getValueOwnershipForSpecifier(getSpecifier());
|
|
}
|
|
|
|
static ValueOwnership getValueOwnershipForSpecifier(Specifier specifier) {
|
|
switch (specifier) {
|
|
case Specifier::Default:
|
|
return ValueOwnership::Default;
|
|
case Specifier::InOut:
|
|
return ValueOwnership::InOut;
|
|
case Specifier::Shared:
|
|
return ValueOwnership::Shared;
|
|
case Specifier::Owned:
|
|
return ValueOwnership::Owned;
|
|
}
|
|
llvm_unreachable("unhandled specifier");
|
|
}
|
|
|
|
static Specifier
|
|
getParameterSpecifierForValueOwnership(ValueOwnership ownership) {
|
|
switch (ownership) {
|
|
case ValueOwnership::Default:
|
|
return Specifier::Default;
|
|
case ValueOwnership::Shared:
|
|
return Specifier::Shared;
|
|
case ValueOwnership::InOut:
|
|
return Specifier::InOut;
|
|
case ValueOwnership::Owned:
|
|
return Specifier::Owned;
|
|
}
|
|
llvm_unreachable("unhandled ownership");
|
|
}
|
|
|
|
SourceRange getSourceRange() const;
|
|
|
|
AnyFunctionType::Param toFunctionParam(Type type = Type()) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Param;
|
|
}
|
|
};
|
|
|
|
/// Describes the kind of subscripting used in Objective-C.
|
|
enum class ObjCSubscriptKind {
|
|
/// Objective-C indexed subscripting, which is based on an integral
|
|
/// index.
|
|
Indexed,
|
|
/// Objective-C keyed subscripting, which is based on an object
|
|
/// argument or metatype thereof.
|
|
Keyed
|
|
};
|
|
|
|
/// Declares a subscripting operator for a type.
|
|
///
|
|
/// A subscript declaration is defined as a get/set pair that produces a
|
|
/// specific type. For example:
|
|
///
|
|
/// \code
|
|
/// subscript (i : Int) -> String {
|
|
/// get { /* return ith String */ }
|
|
/// set { /* set ith string to value */ }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// A type with a subscript declaration can be used as the base of a subscript
|
|
/// expression a[i], where a is of the subscriptable type and i is the type
|
|
/// of the index. A subscript can have multiple indices:
|
|
///
|
|
/// \code
|
|
/// struct Matrix {
|
|
/// subscript (i : Int, j : Int) -> Double {
|
|
/// get { /* return element at position (i, j) */ }
|
|
/// set { /* set element at position (i, j) */ }
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// A given type can have multiple subscript declarations, so long as the
|
|
/// signatures (indices and element type) are distinct.
|
|
///
|
|
class SubscriptDecl : public GenericContext, public AbstractStorageDecl {
|
|
SourceLoc StaticLoc;
|
|
SourceLoc ArrowLoc;
|
|
SourceLoc EndLoc;
|
|
ParameterList *Indices;
|
|
TypeLoc ElementTy;
|
|
|
|
public:
|
|
SubscriptDecl(DeclName Name,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc SubscriptLoc, ParameterList *Indices,
|
|
SourceLoc ArrowLoc, TypeLoc ElementTy, DeclContext *Parent,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::SubscriptDecl, Parent, GenericParams),
|
|
AbstractStorageDecl(DeclKind::Subscript,
|
|
StaticSpelling != StaticSpellingKind::None,
|
|
Parent, Name, SubscriptLoc,
|
|
/*will be overwritten*/ StorageIsNotMutable),
|
|
StaticLoc(StaticLoc), ArrowLoc(ArrowLoc),
|
|
Indices(nullptr), ElementTy(ElementTy) {
|
|
Bits.SubscriptDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
setIndices(Indices);
|
|
}
|
|
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(Bits.SubscriptDecl.StaticSpelling);
|
|
}
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getSubscriptLoc() const { return getNameLoc(); }
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return getStaticLoc().isValid() ? getStaticLoc() : getSubscriptLoc();
|
|
}
|
|
SourceLoc getEndLoc() const { return EndLoc; }
|
|
|
|
void setEndLoc(SourceLoc sl) { EndLoc = sl; }
|
|
SourceRange getSourceRange() const;
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
/// Retrieve the indices for this subscript operation.
|
|
ParameterList *getIndices() { return Indices; }
|
|
const ParameterList *getIndices() const { return Indices; }
|
|
void setIndices(ParameterList *p);
|
|
|
|
/// Retrieve the type of the element referenced by a subscript
|
|
/// operation.
|
|
Type getElementInterfaceType() const;
|
|
TypeLoc &getElementTypeLoc() { return ElementTy; }
|
|
const TypeLoc &getElementTypeLoc() const { return ElementTy; }
|
|
|
|
/// Determine the kind of Objective-C subscripting this declaration
|
|
/// implies.
|
|
ObjCSubscriptKind getObjCSubscriptKind() const;
|
|
|
|
SubscriptDecl *getOverriddenDecl() const {
|
|
return cast_or_null<SubscriptDecl>(
|
|
AbstractStorageDecl::getOverriddenDecl());
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Subscript;
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using 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;
|
|
}
|
|
};
|
|
|
|
/// Base class for function-like declarations.
|
|
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
|
|
friend class NeedsNewVTableEntryRequest;
|
|
|
|
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,
|
|
|
|
/// Function body text was deserialized from a .swiftmodule.
|
|
Deserialized
|
|
|
|
// This enum currently needs to fit in a 3-bit bitfield.
|
|
};
|
|
|
|
BodyKind getBodyKind() const {
|
|
return BodyKind(Bits.AbstractFunctionDecl.BodyKind);
|
|
}
|
|
|
|
struct BodySynthesizer {
|
|
std::pair<BraceStmt *, bool> (* Fn)(AbstractFunctionDecl *, void *);
|
|
void *Context;
|
|
};
|
|
|
|
private:
|
|
ParameterList *Params;
|
|
|
|
protected:
|
|
// If a function has a body at all, we have either a parsed body AST node or
|
|
// we have saved the end location of the unparsed body.
|
|
union {
|
|
/// This enum member is active if getBodyKind() is BodyKind::Parsed or
|
|
/// BodyKind::TypeChecked.
|
|
BraceStmt *Body;
|
|
|
|
/// This enum member is active if getBodyKind() is BodyKind::Deserialized.
|
|
StringRef BodyStringRepresentation;
|
|
|
|
/// This enum member is active if getBodyKind() == BodyKind::Synthesize.
|
|
BodySynthesizer Synthesizer;
|
|
|
|
/// The location of the function body when the body is delayed or skipped.
|
|
///
|
|
/// This enum member is active if getBodyKind() is BodyKind::Unparsed or
|
|
/// BodyKind::Skipped.
|
|
SourceRange BodyRange;
|
|
};
|
|
|
|
friend class ParseAbstractFunctionBodyRequest;
|
|
|
|
CaptureInfo Captures;
|
|
|
|
/// Location of the 'throws' token.
|
|
SourceLoc ThrowsLoc;
|
|
|
|
struct {
|
|
unsigned NeedsNewVTableEntryComputed : 1;
|
|
unsigned NeedsNewVTableEntry : 1;
|
|
} LazySemanticInfo = { };
|
|
|
|
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
|
|
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams)
|
|
: GenericContext(DeclContextKind::AbstractFunctionDecl, Parent, GenericParams),
|
|
ValueDecl(Kind, Parent, Name, NameLoc),
|
|
Body(nullptr), ThrowsLoc(ThrowsLoc) {
|
|
setBodyKind(BodyKind::None);
|
|
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
|
|
Bits.AbstractFunctionDecl.Overridden = false;
|
|
Bits.AbstractFunctionDecl.Throws = Throws;
|
|
Bits.AbstractFunctionDecl.Synthesized = false;
|
|
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
|
|
}
|
|
|
|
void setBodyKind(BodyKind K) {
|
|
Bits.AbstractFunctionDecl.BodyKind = unsigned(K);
|
|
}
|
|
|
|
public:
|
|
void setHasSingleExpressionBody(bool Has = true) {
|
|
Bits.AbstractFunctionDecl.HasSingleExpressionBody = Has;
|
|
}
|
|
|
|
bool hasSingleExpressionBody() const {
|
|
return Bits.AbstractFunctionDecl.HasSingleExpressionBody;
|
|
}
|
|
|
|
Expr *getSingleExpressionBody() const;
|
|
void setSingleExpressionBody(Expr *NewBody);
|
|
|
|
/// 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() : "_";
|
|
}
|
|
|
|
/// Should this declaration be treated as if annotated with transparent
|
|
/// attribute.
|
|
bool isTransparent() const;
|
|
|
|
// Expose our import as member status
|
|
ImportAsMemberStatus getImportAsMemberStatus() const {
|
|
return ImportAsMemberStatus(Bits.AbstractFunctionDecl.IAMStatus);
|
|
}
|
|
bool isImportAsMember() const {
|
|
return getImportAsMemberStatus().isImportAsMember();
|
|
}
|
|
bool isImportAsInstanceMember() const {
|
|
return getImportAsMemberStatus().isInstance();
|
|
}
|
|
bool isImportAsStaticMember() const {
|
|
return getImportAsMemberStatus().isStatic();
|
|
}
|
|
uint8_t getSelfIndex() const {
|
|
return getImportAsMemberStatus().getSelfIndex();
|
|
}
|
|
|
|
void setImportAsStaticMember() {
|
|
auto newValue = getImportAsMemberStatus();
|
|
newValue.setStatic();
|
|
Bits.AbstractFunctionDecl.IAMStatus = newValue.getRawValue();
|
|
}
|
|
void setSelfIndex(uint8_t idx) {
|
|
auto newValue = getImportAsMemberStatus();
|
|
newValue.setSelfIndex(idx);
|
|
Bits.AbstractFunctionDecl.IAMStatus = newValue.getRawValue();
|
|
}
|
|
|
|
/// Retrieve the location of the 'throws' keyword, if present.
|
|
SourceLoc getThrowsLoc() const { return ThrowsLoc; }
|
|
|
|
/// Returns true if the function body throws.
|
|
bool hasThrows() const { return Bits.AbstractFunctionDecl.Throws; }
|
|
|
|
// FIXME: Hack that provides names with keyword arguments for accessors.
|
|
DeclName getEffectiveFullName() const;
|
|
|
|
/// Returns true if the function has a body written in the source file.
|
|
///
|
|
/// Note that a true return value does not imply that the body was actually
|
|
/// parsed.
|
|
bool hasBody() const {
|
|
return getBodyKind() != BodyKind::None &&
|
|
getBodyKind() != BodyKind::Skipped;
|
|
}
|
|
|
|
/// Returns true if the text of this function's body can be retrieved either
|
|
/// by extracting the text from the source buffer or reading the inlinable
|
|
/// body from a deserialized swiftmodule.
|
|
bool hasInlinableBodyText() const;
|
|
|
|
/// Returns the function body, if it was parsed, or nullptr otherwise.
|
|
///
|
|
/// Note that a null return value does not imply that the source code did not
|
|
/// have a body for this function.
|
|
///
|
|
/// \sa hasBody()
|
|
BraceStmt *getBody(bool canSynthesize = true) const;
|
|
|
|
void setBody(BraceStmt *S, BodyKind NewBodyKind = BodyKind::Parsed) {
|
|
assert(getBodyKind() != BodyKind::Skipped &&
|
|
"cannot set a body if it was skipped");
|
|
|
|
Body = S;
|
|
setBodyKind(NewBodyKind);
|
|
}
|
|
|
|
/// Note that the body was skipped for this function. Function body
|
|
/// cannot be attached after this call.
|
|
void setBodySkipped(SourceRange bodyRange) {
|
|
// FIXME: Remove 'Parsed' from this once we can delay parsing function
|
|
// bodies. Right now -experimental-skip-non-inlinable-function-bodies
|
|
// requires being able to change the state from Parsed to Skipped,
|
|
// because we're still eagerly parsing function bodies.
|
|
assert(getBodyKind() == BodyKind::None ||
|
|
getBodyKind() == BodyKind::Unparsed ||
|
|
getBodyKind() == BodyKind::Parsed);
|
|
assert(bodyRange.isValid());
|
|
BodyRange = bodyRange;
|
|
setBodyKind(BodyKind::Skipped);
|
|
}
|
|
|
|
/// Note that parsing for the body was delayed.
|
|
void setBodyDelayed(SourceRange bodyRange) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
assert(bodyRange.isValid());
|
|
BodyRange = bodyRange;
|
|
setBodyKind(BodyKind::Unparsed);
|
|
}
|
|
|
|
/// Provide the parsed body for the function.
|
|
void setBodyParsed(BraceStmt *S) {
|
|
setBody(S, BodyKind::Parsed);
|
|
}
|
|
|
|
/// Note that parsing for the body was delayed.
|
|
///
|
|
/// The function should return the body statement and a flag indicating
|
|
/// whether that body is already type-checked.
|
|
void setBodySynthesizer(
|
|
std::pair<BraceStmt *, bool> (* fn)(AbstractFunctionDecl *, void *),
|
|
void *context = nullptr) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
Synthesizer = {fn, context};
|
|
setBodyKind(BodyKind::Synthesize);
|
|
}
|
|
|
|
/// Note that this is a memberwise initializer and thus the body will be
|
|
/// generated by SILGen.
|
|
void setIsMemberwiseInitializer() {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
assert(isa<ConstructorDecl>(this));
|
|
setBodyKind(BodyKind::MemberwiseInitializer);
|
|
}
|
|
|
|
/// Gets the body of this function, stripping the unused portions of #if
|
|
/// configs inside the body. If this function was not deserialized from a
|
|
/// .swiftmodule, this body is reconstructed from the original
|
|
/// source buffer.
|
|
StringRef getInlinableBodyText(SmallVectorImpl<char> &scratch) const;
|
|
|
|
void setBodyStringRepresentation(StringRef body) {
|
|
assert(getBodyKind() == BodyKind::None);
|
|
setBodyKind(BodyKind::Deserialized);
|
|
BodyStringRepresentation = body;
|
|
}
|
|
|
|
bool isBodyTypeChecked() const {
|
|
return getBodyKind() == BodyKind::TypeChecked;
|
|
}
|
|
|
|
bool isBodySkipped() const {
|
|
return getBodyKind() == BodyKind::Skipped;
|
|
}
|
|
|
|
bool isMemberwiseInitializer() const {
|
|
return getBodyKind() == BodyKind::MemberwiseInitializer;
|
|
}
|
|
|
|
/// For a method of a class, checks whether it will require a new entry in the
|
|
/// vtable.
|
|
bool needsNewVTableEntry() const;
|
|
|
|
bool isEffectiveLinkageMoreVisibleThan(ValueDecl *other) const {
|
|
return (std::min(getEffectiveAccess(), AccessLevel::Public) >
|
|
std::min(other->getEffectiveAccess(), AccessLevel::Public));
|
|
}
|
|
|
|
bool isSynthesized() const {
|
|
return Bits.AbstractFunctionDecl.Synthesized;
|
|
}
|
|
|
|
void setSynthesized(bool value = true) {
|
|
Bits.AbstractFunctionDecl.Synthesized = value;
|
|
}
|
|
|
|
public:
|
|
/// Compute the interface type of this function declaration from the
|
|
/// parameter types.
|
|
void computeType(AnyFunctionType::ExtInfo Info = FunctionType::ExtInfo());
|
|
|
|
/// Retrieve the source range of the function body.
|
|
SourceRange getBodySourceRange() const;
|
|
|
|
/// Retrieve the source range of the function declaration name + patterns.
|
|
SourceRange getSignatureSourceRange() const;
|
|
|
|
CaptureInfo getCaptureInfo() const { return Captures; }
|
|
void setCaptureInfo(CaptureInfo captures) { Captures = captures; }
|
|
|
|
/// Retrieve the Objective-C selector that names this method.
|
|
ObjCSelector getObjCSelector(DeclName preferredName = DeclName(),
|
|
bool skipIsObjCResolution = false) const;
|
|
|
|
/// Determine whether the given method would produce an Objective-C
|
|
/// instance method.
|
|
bool isObjCInstanceMethod() const;
|
|
|
|
/// Determine whether the name of an argument is an API name by default
|
|
/// depending on the function context.
|
|
bool argumentNameIsAPIByDefault() const;
|
|
|
|
/// Retrieve the function's parameter list, not including 'self' if present.
|
|
ParameterList *getParameters() {
|
|
return Params;
|
|
}
|
|
const ParameterList *getParameters() const {
|
|
return Params;
|
|
}
|
|
|
|
void setParameters(ParameterList *Params);
|
|
|
|
bool hasImplicitSelfDecl() const {
|
|
return Bits.AbstractFunctionDecl.HasImplicitSelfDecl;
|
|
}
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Retrieve the implicit 'self' parameter for methods. Returns nullptr for
|
|
/// free functions.
|
|
const ParamDecl *getImplicitSelfDecl(bool createIfNeeded=true) const {
|
|
return const_cast<AbstractFunctionDecl*>(this)
|
|
->getImplicitSelfDecl(createIfNeeded);
|
|
}
|
|
ParamDecl *getImplicitSelfDecl(bool createIfNeeded=true);
|
|
|
|
/// Retrieve the declaration that this method overrides, if any.
|
|
AbstractFunctionDecl *getOverriddenDecl() const {
|
|
return cast_or_null<AbstractFunctionDecl>(ValueDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Whether the declaration is later overridden in the module
|
|
///
|
|
/// Overrides are resolved during type checking; only query this field after
|
|
/// the whole module has been checked
|
|
bool isOverridden() const { return Bits.AbstractFunctionDecl.Overridden; }
|
|
|
|
/// The declaration has been overridden in the module
|
|
///
|
|
/// Resolved during type checking
|
|
void setIsOverridden() { Bits.AbstractFunctionDecl.Overridden = true; }
|
|
|
|
/// Set information about the foreign error convention used by this
|
|
/// declaration.
|
|
void setForeignErrorConvention(const ForeignErrorConvention &convention);
|
|
|
|
/// Get information about the foreign error convention used by this
|
|
/// declaration, given that it is @objc and 'throws'.
|
|
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->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the declaration is forced to be statically dispatched.
|
|
bool hasForcedStaticDispatch() const;
|
|
|
|
/// Get the type of this declaration without the Self clause.
|
|
/// Asserts if not in type context.
|
|
Type getMethodInterfaceType() const;
|
|
|
|
/// Tests if this is a function returning a DynamicSelfType, or a
|
|
/// constructor.
|
|
bool hasDynamicSelfResult() const;
|
|
|
|
using DeclContext::operator new;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
class OperatorDecl;
|
|
|
|
enum class SelfAccessKind : uint8_t {
|
|
NonMutating,
|
|
Mutating,
|
|
Consuming,
|
|
};
|
|
|
|
/// Diagnostic printing of \c SelfAccessKind.
|
|
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK);
|
|
|
|
/// FuncDecl - 'func' declaration.
|
|
class FuncDecl : public AbstractFunctionDecl {
|
|
friend class AbstractFunctionDecl;
|
|
friend class SelfAccessKindRequest;
|
|
friend class IsStaticRequest;
|
|
|
|
SourceLoc StaticLoc; // Location of the 'static' token or invalid.
|
|
SourceLoc FuncLoc; // Location of the 'func' token.
|
|
|
|
TypeLoc FnRetType;
|
|
|
|
protected:
|
|
FuncDecl(DeclKind Kind,
|
|
SourceLoc StaticLoc, StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
bool HasImplicitSelfDecl,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: AbstractFunctionDecl(Kind, Parent,
|
|
Name, NameLoc,
|
|
Throws, ThrowsLoc,
|
|
HasImplicitSelfDecl, GenericParams),
|
|
StaticLoc(StaticLoc), FuncLoc(FuncLoc) {
|
|
assert(!Name.getBaseName().isSpecial());
|
|
|
|
Bits.FuncDecl.StaticSpelling = static_cast<unsigned>(StaticSpelling);
|
|
|
|
Bits.FuncDecl.ForcedStaticDispatch = false;
|
|
Bits.FuncDecl.SelfAccess =
|
|
static_cast<unsigned>(SelfAccessKind::NonMutating);
|
|
Bits.FuncDecl.SelfAccessComputed = false;
|
|
Bits.FuncDecl.IsStaticComputed = false;
|
|
Bits.FuncDecl.IsStatic = false;
|
|
}
|
|
|
|
private:
|
|
static FuncDecl *createImpl(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent,
|
|
ClangNode ClangN);
|
|
|
|
Optional<SelfAccessKind> getCachedSelfAccessKind() const {
|
|
if (Bits.FuncDecl.SelfAccessComputed)
|
|
return static_cast<SelfAccessKind>(Bits.FuncDecl.SelfAccess);
|
|
|
|
return None;
|
|
}
|
|
|
|
Optional<bool> getCachedIsStatic() const {
|
|
if (Bits.FuncDecl.IsStaticComputed)
|
|
return Bits.FuncDecl.IsStatic;
|
|
|
|
return None;
|
|
}
|
|
|
|
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,
|
|
DeclContext *Parent);
|
|
|
|
static FuncDecl *create(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
GenericParamList *GenericParams,
|
|
ParameterList *ParameterList,
|
|
TypeLoc FnRetType, DeclContext *Parent,
|
|
ClangNode ClangN = ClangNode());
|
|
|
|
Identifier getName() const { return getFullName().getBaseIdentifier(); }
|
|
|
|
bool isStatic() const;
|
|
|
|
/// \returns the way 'static'/'class' was spelled in the source.
|
|
StaticSpellingKind getStaticSpelling() const {
|
|
return static_cast<StaticSpellingKind>(Bits.FuncDecl.StaticSpelling);
|
|
}
|
|
/// \returns the way 'static'/'class' should be spelled for this declaration.
|
|
StaticSpellingKind getCorrectStaticSpelling() const;
|
|
void setStatic(bool IsStatic = true) {
|
|
Bits.FuncDecl.IsStaticComputed = true;
|
|
Bits.FuncDecl.IsStatic = IsStatic;
|
|
}
|
|
|
|
bool isMutating() const {
|
|
return getSelfAccessKind() == SelfAccessKind::Mutating;
|
|
}
|
|
bool isNonMutating() const {
|
|
return getSelfAccessKind() == SelfAccessKind::NonMutating;
|
|
}
|
|
bool isConsuming() const {
|
|
return getSelfAccessKind() == SelfAccessKind::Consuming;
|
|
}
|
|
bool isCallAsFunctionMethod() const;
|
|
|
|
SelfAccessKind getSelfAccessKind() const;
|
|
|
|
void setSelfAccessKind(SelfAccessKind mod) {
|
|
Bits.FuncDecl.SelfAccess = static_cast<unsigned>(mod);
|
|
Bits.FuncDecl.SelfAccessComputed = true;
|
|
}
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getFuncLoc() const { return FuncLoc; }
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return StaticLoc.isValid() && !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;
|
|
|
|
void getLocalCaptures(SmallVectorImpl<CapturedValue> &Result) const {
|
|
return getCaptureInfo().getLocalCaptures(Result);
|
|
}
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage();
|
|
|
|
/// Get the supertype method this method overrides, if any.
|
|
FuncDecl *getOverriddenDecl() const {
|
|
return cast_or_null<FuncDecl>(AbstractFunctionDecl::getOverriddenDecl());
|
|
}
|
|
|
|
OperatorDecl *getOperatorDecl() const;
|
|
|
|
/// Returns true if the function is forced to be statically dispatched.
|
|
bool hasForcedStaticDispatch() const {
|
|
return Bits.FuncDecl.ForcedStaticDispatch;
|
|
}
|
|
void setForcedStaticDispatch(bool flag) {
|
|
Bits.FuncDecl.ForcedStaticDispatch = flag;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Func ||
|
|
D->getKind() == DeclKind::Accessor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
/// True if the function is a defer body.
|
|
bool isDeferBody() const;
|
|
|
|
/// Perform basic checking to determine whether the @IBAction or
|
|
/// @IBSegueAction attribute can be applied to this function.
|
|
bool isPotentialIBActionTarget() const;
|
|
};
|
|
|
|
/// This represents an accessor function, such as a getter or setter.
|
|
class AccessorDecl final : public FuncDecl {
|
|
/// Location of the accessor keyword, e.g. 'set'.
|
|
SourceLoc AccessorKeywordLoc;
|
|
|
|
AbstractStorageDecl *Storage;
|
|
|
|
AccessorDecl(SourceLoc declLoc, SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind, AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc, StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
bool hasImplicitSelfDecl, GenericParamList *genericParams,
|
|
DeclContext *parent)
|
|
: FuncDecl(DeclKind::Accessor,
|
|
staticLoc, staticSpelling, /*func loc*/ declLoc,
|
|
/*name*/ Identifier(), /*name loc*/ declLoc,
|
|
throws, throwsLoc, hasImplicitSelfDecl, genericParams, parent),
|
|
AccessorKeywordLoc(accessorKeywordLoc),
|
|
Storage(storage) {
|
|
Bits.AccessorDecl.AccessorKind = unsigned(accessorKind);
|
|
}
|
|
|
|
static AccessorDecl *createImpl(ASTContext &ctx,
|
|
SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
GenericParamList *genericParams,
|
|
DeclContext *parent,
|
|
ClangNode clangNode);
|
|
|
|
Optional<bool> getCachedIsTransparent() const {
|
|
if (Bits.AccessorDecl.IsTransparentComputed)
|
|
return Bits.AccessorDecl.IsTransparent;
|
|
return None;
|
|
}
|
|
|
|
friend class IsAccessorTransparentRequest;
|
|
|
|
public:
|
|
static AccessorDecl *createDeserialized(ASTContext &ctx,
|
|
SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
GenericParamList *genericParams,
|
|
DeclContext *parent);
|
|
|
|
static AccessorDecl *create(ASTContext &ctx, SourceLoc declLoc,
|
|
SourceLoc accessorKeywordLoc,
|
|
AccessorKind accessorKind,
|
|
AbstractStorageDecl *storage,
|
|
SourceLoc staticLoc,
|
|
StaticSpellingKind staticSpelling,
|
|
bool throws, SourceLoc throwsLoc,
|
|
GenericParamList *genericParams,
|
|
ParameterList *parameterList,
|
|
TypeLoc fnRetType, DeclContext *parent,
|
|
ClangNode clangNode = ClangNode());
|
|
|
|
SourceLoc getAccessorKeywordLoc() const { return AccessorKeywordLoc; }
|
|
|
|
AbstractStorageDecl *getStorage() const {
|
|
return Storage;
|
|
}
|
|
|
|
AccessorKind getAccessorKind() const {
|
|
return AccessorKind(Bits.AccessorDecl.AccessorKind);
|
|
}
|
|
|
|
bool isGetter() const { return getAccessorKind() == AccessorKind::Get; }
|
|
bool isSetter() const { return getAccessorKind() == AccessorKind::Set; }
|
|
bool isAnyAddressor() const {
|
|
auto kind = getAccessorKind();
|
|
return kind == AccessorKind::Address
|
|
|| kind == AccessorKind::MutableAddress;
|
|
}
|
|
|
|
/// isGetterOrSetter - Determine whether this is specifically a getter or
|
|
/// a setter, as opposed to some other kind of accessor.
|
|
///
|
|
/// For example, only getters and setters can be exposed to Objective-C.
|
|
bool isGetterOrSetter() const { return isGetter() || isSetter(); }
|
|
|
|
bool isObservingAccessor() const {
|
|
switch (getAccessorKind()) {
|
|
#define OBSERVING_ACCESSOR(ID, KEYWORD) \
|
|
case AccessorKind::ID: return true;
|
|
#define ACCESSOR(ID) \
|
|
case AccessorKind::ID: return false;
|
|
#include "swift/AST/AccessorKinds.def"
|
|
}
|
|
llvm_unreachable("bad accessor kind");
|
|
}
|
|
|
|
/// \returns true if this is non-mutating due to applying a 'mutating'
|
|
/// attribute. For example a "mutating set" accessor.
|
|
bool isExplicitNonMutating() const;
|
|
|
|
/// Is the accesor one of the kinds that's assumed nonmutating by default?
|
|
bool isAssumedNonMutating() const;
|
|
|
|
/// Is this accessor one of the kinds that's implicitly a coroutine?
|
|
bool isCoroutine() const {
|
|
switch (getAccessorKind()) {
|
|
#define COROUTINE_ACCESSOR(ID, KEYWORD) \
|
|
case AccessorKind::ID: return true;
|
|
#define ACCESSOR(ID) \
|
|
case AccessorKind::ID: return false;
|
|
#include "swift/AST/AccessorKinds.def"
|
|
}
|
|
llvm_unreachable("bad accessor kind");
|
|
}
|
|
|
|
void setIsTransparent(bool transparent) {
|
|
Bits.AccessorDecl.IsTransparent = transparent;
|
|
Bits.AccessorDecl.IsTransparentComputed = 1;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Accessor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
inline AccessorDecl *
|
|
AbstractStorageDecl::AccessorRecord::getAccessor(AccessorKind kind) const {
|
|
if (auto optIndex = AccessorIndices[unsigned(kind)]) {
|
|
auto accessor = getAllAccessors()[optIndex - 1];
|
|
assert(accessor && accessor->getAccessorKind() == kind);
|
|
return accessor;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
/// This represents a 'case' declaration in an 'enum', which may declare
|
|
/// one or more individual comma-separated EnumElementDecls.
|
|
class EnumCaseDecl final : public Decl,
|
|
private llvm::TrailingObjects<EnumCaseDecl, EnumElementDecl *> {
|
|
friend TrailingObjects;
|
|
friend class Decl;
|
|
SourceLoc CaseLoc;
|
|
|
|
EnumCaseDecl(SourceLoc CaseLoc,
|
|
ArrayRef<EnumElementDecl *> Elements,
|
|
DeclContext *DC)
|
|
: Decl(DeclKind::EnumCase, DC),
|
|
CaseLoc(CaseLoc)
|
|
{
|
|
Bits.EnumCaseDecl.NumElements = Elements.size();
|
|
std::uninitialized_copy(Elements.begin(), Elements.end(),
|
|
getTrailingObjects<EnumElementDecl *>());
|
|
}
|
|
SourceLoc getLocFromSource() const { return CaseLoc; }
|
|
|
|
public:
|
|
static EnumCaseDecl *create(SourceLoc CaseLoc,
|
|
ArrayRef<EnumElementDecl*> Elements,
|
|
DeclContext *DC);
|
|
|
|
/// Get the list of elements declared in this case.
|
|
ArrayRef<EnumElementDecl *> getElements() const {
|
|
return {getTrailingObjects<EnumElementDecl *>(),
|
|
Bits.EnumCaseDecl.NumElements};
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumCase;
|
|
}
|
|
};
|
|
|
|
/// This represents a single case of an 'enum' declaration.
|
|
///
|
|
/// For example, the X, Y, and Z in this enum:
|
|
///
|
|
/// \code
|
|
/// enum V {
|
|
/// case X(Int), Y(Int)
|
|
/// case Z
|
|
/// }
|
|
/// \endcode
|
|
///
|
|
/// The type of an EnumElementDecl is always the EnumType for the containing
|
|
/// enum. EnumElementDecls are represented in the AST as members of their
|
|
/// parent EnumDecl, although syntactically they are subordinate to the
|
|
/// EnumCaseDecl.
|
|
class EnumElementDecl : public DeclContext, public ValueDecl {
|
|
friend class EnumRawValuesRequest;
|
|
|
|
/// 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;
|
|
|
|
public:
|
|
EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name,
|
|
ParameterList *Params,
|
|
SourceLoc EqualsLoc,
|
|
LiteralExpr *RawValueExpr,
|
|
DeclContext *DC);
|
|
|
|
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() : "_";
|
|
}
|
|
|
|
Type getArgumentInterfaceType() const;
|
|
|
|
void setParameterList(ParameterList *params);
|
|
ParameterList *getParameterList() const { return Params; }
|
|
|
|
/// Retrieves a fully typechecked raw value expression associated
|
|
/// with this enum element, if it exists.
|
|
LiteralExpr *getRawValueExpr() const;
|
|
|
|
/// Retrieves a "structurally" checked raw value expression associated
|
|
/// with this enum element, if it exists.
|
|
///
|
|
/// The structural raw value may or may not have a type set, but it is
|
|
/// guaranteed to be suitable for retrieving any non-semantic information
|
|
/// like digit text for an integral raw value or user text for a string raw value.
|
|
LiteralExpr *getStructuralRawValueExpr() const;
|
|
|
|
/// Reset the raw value expression.
|
|
void setRawValueExpr(LiteralExpr *e);
|
|
|
|
/// Return the containing EnumDecl.
|
|
EnumDecl *getParentEnum() const {
|
|
return cast<EnumDecl>(getDeclContext());
|
|
}
|
|
|
|
/// Return the containing EnumCaseDecl.
|
|
EnumCaseDecl *getParentCase() const;
|
|
|
|
SourceLoc getStartLoc() const {
|
|
return getNameLoc();
|
|
}
|
|
SourceRange getSourceRange() const;
|
|
|
|
bool hasAssociatedValues() const {
|
|
return getParameterList() != nullptr;
|
|
}
|
|
|
|
/// True if the case is marked 'indirect'.
|
|
bool isIndirect() const {
|
|
return getAttrs().hasAttribute<IndirectAttr>();
|
|
}
|
|
|
|
/// Do not call this!
|
|
/// It exists to let the AST walkers get the raw value without forcing a request.
|
|
LiteralExpr *getRawValueUnchecked() const { return RawValueExpr; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::EnumElement;
|
|
}
|
|
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
|
|
using DeclContext::operator new;
|
|
using Decl::getASTContext;
|
|
};
|
|
|
|
inline SourceRange EnumCaseDecl::getSourceRange() const {
|
|
auto subRange = getElements().back()->getSourceRange();
|
|
if (subRange.isValid())
|
|
return {CaseLoc, subRange.End};
|
|
return {};
|
|
}
|
|
|
|
/// Describes the kind of initializer.
|
|
enum class CtorInitializerKind {
|
|
/// A designated initializer is an initializer responsible for initializing
|
|
/// the stored properties of the current class and chaining to a superclass's
|
|
/// designated initializer (for non-root classes).
|
|
///
|
|
/// Designated initializers are never inherited.
|
|
Designated,
|
|
|
|
/// A convenience initializer is an initializer that initializes a complete
|
|
/// object by delegating to another initializer (eventually reaching a
|
|
/// designated initializer).
|
|
///
|
|
/// Convenience initializers are inherited into subclasses that override
|
|
/// all of their superclass's designated initializers.
|
|
Convenience,
|
|
|
|
/// A convenience factory initializer is a convenience initializer introduced
|
|
/// by an imported Objective-C factory method.
|
|
///
|
|
/// Convenience factory initializers cannot be expressed directly in
|
|
/// Swift; rather, they are produced by the Clang importer when importing
|
|
/// an instancetype factory method from Objective-C.
|
|
ConvenienceFactory,
|
|
|
|
/// A factory initializer is an initializer that is neither designated nor
|
|
/// convenience: it can be used to create an object of the given type, but
|
|
/// cannot be chained to via "super.init" nor is it inherited.
|
|
///
|
|
/// A factory initializer is written with a return type of the class name
|
|
/// itself. FIXME: However, this is only a presentation form, and at present
|
|
/// the only factory initializers are produced by importing an Objective-C
|
|
/// factory method that does not return instancetype.
|
|
///
|
|
/// FIXME: Arguably, structs and enums only have factory initializers, and
|
|
/// using designated initializers for them is a misnomer.
|
|
Factory
|
|
};
|
|
|
|
/// ConstructorDecl - Declares a constructor for a type. For example:
|
|
///
|
|
/// \code
|
|
/// struct X {
|
|
/// var x : Int
|
|
/// init(i : Int) {
|
|
/// x = i
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
class ConstructorDecl : public AbstractFunctionDecl {
|
|
/// The location of the '!' or '?' for a failable initializer.
|
|
SourceLoc FailabilityLoc;
|
|
|
|
ParamDecl *SelfDecl;
|
|
|
|
/// The interface type of the initializing constructor.
|
|
Type InitializerInterfaceType;
|
|
|
|
/// The typechecked call to super.init expression, which needs to be
|
|
/// inserted at the end of the initializer by SILGen.
|
|
Expr *CallToSuperInit = nullptr;
|
|
|
|
public:
|
|
ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
|
|
bool Failable, SourceLoc FailabilityLoc,
|
|
bool Throws, SourceLoc ThrowsLoc,
|
|
ParameterList *BodyParams,
|
|
GenericParamList *GenericParams,
|
|
DeclContext *Parent);
|
|
|
|
SourceLoc getConstructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getConstructorLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Get the interface type of the constructed object.
|
|
Type getResultInterfaceType() const;
|
|
|
|
/// Get the interface type of the initializing constructor.
|
|
Type getInitializerInterfaceType();
|
|
|
|
/// Get the typechecked call to super.init expression, which needs to be
|
|
/// inserted at the end of the initializer by SILGen.
|
|
Expr *getSuperInitCall() { return CallToSuperInit; }
|
|
void setSuperInitCall(Expr *CallExpr) { CallToSuperInit = CallExpr; }
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage() { return &SelfDecl; }
|
|
|
|
/// 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;
|
|
|
|
/// Whether this is a designated initializer.
|
|
bool isDesignatedInit() const {
|
|
return getInitKind() == CtorInitializerKind::Designated;
|
|
}
|
|
|
|
/// Whether this is a convenience initializer.
|
|
bool isConvenienceInit() const {
|
|
return getInitKind() == CtorInitializerKind::Convenience ||
|
|
getInitKind() == CtorInitializerKind::ConvenienceFactory;
|
|
}
|
|
|
|
/// Whether this is a factory initializer.
|
|
bool isFactoryInit() const {
|
|
switch (getInitKind()) {
|
|
case CtorInitializerKind::Designated:
|
|
case CtorInitializerKind::Convenience:
|
|
return false;
|
|
|
|
case CtorInitializerKind::Factory:
|
|
case CtorInitializerKind::ConvenienceFactory:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad CtorInitializerKind");
|
|
}
|
|
|
|
/// Determine whether this initializer is inheritable.
|
|
bool isInheritable() const {
|
|
switch (getInitKind()) {
|
|
case CtorInitializerKind::Designated:
|
|
case CtorInitializerKind::Factory:
|
|
return false;
|
|
|
|
case CtorInitializerKind::Convenience:
|
|
case CtorInitializerKind::ConvenienceFactory:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad CtorInitializerKind");
|
|
}
|
|
|
|
/// Determine if this is a failable initializer.
|
|
bool isFailable() const {
|
|
return Bits.ConstructorDecl.Failable;
|
|
}
|
|
|
|
/// Retrieve the location of the '!' or '?' in a failable initializer.
|
|
SourceLoc getFailabilityLoc() const { return FailabilityLoc; }
|
|
|
|
/// Whether the implementation of this method is a stub that traps at runtime.
|
|
bool hasStubImplementation() const {
|
|
return Bits.ConstructorDecl.HasStubImplementation;
|
|
}
|
|
|
|
/// Set whether the implementation of this method is a stub that
|
|
/// traps at runtime.
|
|
void setStubImplementation(bool stub) {
|
|
Bits.ConstructorDecl.HasStubImplementation = stub;
|
|
}
|
|
|
|
ConstructorDecl *getOverriddenDecl() const {
|
|
return cast_or_null<ConstructorDecl>(
|
|
AbstractFunctionDecl::getOverriddenDecl());
|
|
}
|
|
|
|
/// Determine whether this initializer falls into the special case for
|
|
/// Objective-C initializers with selectors longer than "init", e.g.,
|
|
/// \c initForMemory.
|
|
///
|
|
/// In such cases, one can write the Swift initializer
|
|
/// with a single parameter of type '()', e.g,
|
|
///
|
|
/// \code
|
|
/// @objc init(forMemory: ())
|
|
/// \endcode
|
|
bool isObjCZeroParameterWithLongSelector() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Constructor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// DestructorDecl - Declares a destructor for a type. For example:
|
|
///
|
|
/// \code
|
|
/// struct X {
|
|
/// var fd : Int
|
|
/// deinit {
|
|
/// close(fd)
|
|
/// }
|
|
/// }
|
|
/// \endcode
|
|
class DestructorDecl : public AbstractFunctionDecl {
|
|
ParamDecl *SelfDecl;
|
|
|
|
public:
|
|
DestructorDecl(SourceLoc DestructorLoc, DeclContext *Parent);
|
|
|
|
ParamDecl **getImplicitSelfDeclStorage() { return &SelfDecl; }
|
|
|
|
SourceLoc getDestructorLoc() const { return getNameLoc(); }
|
|
SourceLoc getStartLoc() const { return getDestructorLoc(); }
|
|
SourceRange getSourceRange() const;
|
|
|
|
/// Retrieve the Objective-C selector for destructors.
|
|
ObjCSelector getObjCSelector() const;
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Destructor;
|
|
}
|
|
static bool classof(const AbstractFunctionDecl *D) {
|
|
return classof(static_cast<const Decl*>(D));
|
|
}
|
|
static bool classof(const DeclContext *DC) {
|
|
if (auto D = DC->getAsDecl())
|
|
return classof(D);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/// Declares a precedence group. For example:
|
|
///
|
|
/// \code
|
|
/// precedencegroup MultiplicativePrecedence {
|
|
/// associativity: right
|
|
/// higherThan: AdditivePrecedence
|
|
/// }
|
|
/// \endcode
|
|
class PrecedenceGroupDecl : public Decl {
|
|
public:
|
|
struct Relation {
|
|
SourceLoc NameLoc;
|
|
Identifier Name;
|
|
PrecedenceGroupDecl *Group;
|
|
};
|
|
|
|
private:
|
|
SourceLoc PrecedenceGroupLoc, NameLoc, LBraceLoc, RBraceLoc;
|
|
SourceLoc AssociativityKeywordLoc, AssociativityValueLoc;
|
|
SourceLoc AssignmentKeywordLoc, AssignmentValueLoc;
|
|
SourceLoc HigherThanLoc, LowerThanLoc;
|
|
Identifier Name;
|
|
unsigned NumHigherThan, NumLowerThan;
|
|
// Tail-allocated array of Relations
|
|
|
|
Relation *getHigherThanBuffer() {
|
|
return reinterpret_cast<Relation*>(this + 1);
|
|
}
|
|
const Relation *getHigherThanBuffer() const {
|
|
return reinterpret_cast<const Relation*>(this + 1);
|
|
}
|
|
Relation *getLowerThanBuffer() {
|
|
return getHigherThanBuffer() + NumHigherThan;
|
|
}
|
|
const Relation *getLowerThanBuffer() const {
|
|
return getHigherThanBuffer() + NumHigherThan;
|
|
}
|
|
|
|
PrecedenceGroupDecl(DeclContext *DC,
|
|
SourceLoc precedenceGroupLoc,
|
|
SourceLoc nameLoc, Identifier name,
|
|
SourceLoc lbraceLoc,
|
|
SourceLoc associativityKeywordLoc,
|
|
SourceLoc associativityValueLoc,
|
|
Associativity associativity,
|
|
SourceLoc assignmentKeywordLoc,
|
|
SourceLoc assignmentValueLoc,
|
|
bool isAssignment,
|
|
SourceLoc higherThanLoc, ArrayRef<Relation> higherThan,
|
|
SourceLoc lowerThanLoc, ArrayRef<Relation> lowerThan,
|
|
SourceLoc rbraceLoc);
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
public:
|
|
static PrecedenceGroupDecl *create(DeclContext *dc,
|
|
SourceLoc precedenceGroupLoc,
|
|
SourceLoc nameLoc,
|
|
Identifier name,
|
|
SourceLoc lbraceLoc,
|
|
SourceLoc associativityKeywordLoc,
|
|
SourceLoc associativityValueLoc,
|
|
Associativity associativity,
|
|
SourceLoc assignmentKeywordLoc,
|
|
SourceLoc assignmentValueLoc,
|
|
bool isAssignment,
|
|
SourceLoc higherThanLoc,
|
|
ArrayRef<Relation> higherThan,
|
|
SourceLoc lowerThanLoc,
|
|
ArrayRef<Relation> lowerThan,
|
|
SourceLoc rbraceLoc);
|
|
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { PrecedenceGroupLoc, RBraceLoc };
|
|
}
|
|
|
|
/// Return the location of 'precedencegroup' in:
|
|
/// precedencegroup MultiplicativePrecedence { ... }
|
|
SourceLoc getPrecedenceGroupLoc() const { return PrecedenceGroupLoc; }
|
|
|
|
/// Return the location of 'MultiplicativePrecedence' in:
|
|
/// precedencegroup MultiplicativePrecedence { ... }
|
|
SourceLoc getNameLoc() const {
|
|
return NameLoc;
|
|
}
|
|
|
|
Identifier getName() const {
|
|
return Name;
|
|
}
|
|
|
|
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;
|
|
|
|
ArrayRef<Identifier> Identifiers;
|
|
ArrayRef<SourceLoc> IdentifierLocs;
|
|
ArrayRef<NominalTypeDecl *> DesignatedNominalTypes;
|
|
SourceLoc getLocFromSource() const { return NameLoc; }
|
|
friend class Decl;
|
|
public:
|
|
OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc,
|
|
Identifier Name, SourceLoc NameLoc,
|
|
ArrayRef<Identifier> Identifiers,
|
|
ArrayRef<SourceLoc> IdentifierLocs)
|
|
: Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name),
|
|
Identifiers(Identifiers), IdentifierLocs(IdentifierLocs) {}
|
|
|
|
OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc,
|
|
Identifier Name, SourceLoc NameLoc,
|
|
ArrayRef<NominalTypeDecl *> DesignatedNominalTypes)
|
|
: Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name),
|
|
DesignatedNominalTypes(DesignatedNominalTypes) {}
|
|
|
|
|
|
SourceLoc getOperatorLoc() const { return OperatorLoc; }
|
|
SourceLoc getNameLoc() const { return NameLoc; }
|
|
Identifier getName() const { return name; }
|
|
|
|
ArrayRef<Identifier> getIdentifiers() const {
|
|
return Identifiers;
|
|
}
|
|
|
|
ArrayRef<SourceLoc> getIdentifierLocs() const {
|
|
return IdentifierLocs;
|
|
}
|
|
|
|
ArrayRef<NominalTypeDecl *> getDesignatedNominalTypes() const {
|
|
return DesignatedNominalTypes;
|
|
}
|
|
|
|
void setDesignatedNominalTypes(ArrayRef<NominalTypeDecl *> nominalTypes) {
|
|
DesignatedNominalTypes = nominalTypes;
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
// Workaround: http://llvm.org/PR35906
|
|
if (DeclKind::Last_Decl == DeclKind::Last_OperatorDecl)
|
|
return D->getKind() >= DeclKind::First_OperatorDecl;
|
|
return D->getKind() >= DeclKind::First_OperatorDecl
|
|
&& D->getKind() <= DeclKind::Last_OperatorDecl;
|
|
}
|
|
};
|
|
|
|
/// Declares the behavior of an infix operator. For example:
|
|
///
|
|
/// \code
|
|
/// infix operator /+/ : AdditionPrecedence, Numeric
|
|
/// \endcode
|
|
class InfixOperatorDecl : public OperatorDecl {
|
|
SourceLoc ColonLoc;
|
|
|
|
public:
|
|
InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name,
|
|
SourceLoc nameLoc, SourceLoc colonLoc,
|
|
ArrayRef<Identifier> identifiers,
|
|
ArrayRef<SourceLoc> identifierLocs)
|
|
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc,
|
|
identifiers, identifierLocs),
|
|
ColonLoc(colonLoc) {}
|
|
|
|
SourceLoc getEndLoc() const {
|
|
auto identifierLocs = getIdentifierLocs();
|
|
if (identifierLocs.empty())
|
|
return getNameLoc();
|
|
|
|
return identifierLocs.back();
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return { getOperatorLoc(), getEndLoc() };
|
|
}
|
|
|
|
SourceLoc getColonLoc() const { return ColonLoc; }
|
|
|
|
PrecedenceGroupDecl *getPrecedenceGroup() const;
|
|
|
|
/// 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,
|
|
ArrayRef<Identifier> Identifiers,
|
|
ArrayRef<SourceLoc> IdentifierLocs)
|
|
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc,
|
|
Identifiers, IdentifierLocs) {}
|
|
|
|
PrefixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
|
|
SourceLoc NameLoc,
|
|
ArrayRef<NominalTypeDecl *> designatedNominalTypes)
|
|
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc,
|
|
designatedNominalTypes) {}
|
|
|
|
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,
|
|
ArrayRef<Identifier> Identifiers,
|
|
ArrayRef<SourceLoc> IdentifierLocs)
|
|
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc,
|
|
Identifiers, IdentifierLocs) {}
|
|
|
|
PostfixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
|
|
SourceLoc NameLoc,
|
|
ArrayRef<NominalTypeDecl *> designatedNominalTypes)
|
|
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc,
|
|
designatedNominalTypes) {}
|
|
|
|
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();
|
|
}
|
|
friend class Decl;
|
|
SourceLoc getLocFromSource() const {
|
|
return SourceLoc();
|
|
}
|
|
public:
|
|
static MissingMemberDecl *
|
|
create(ASTContext &ctx, DeclContext *DC, DeclName name,
|
|
unsigned numVTableEntries, bool hasStorage) {
|
|
assert(!numVTableEntries || isa<ProtocolDecl>(DC) || isa<ClassDecl>(DC) &&
|
|
"Only classes and protocols have vtable/witness table entries");
|
|
assert(!hasStorage || !isa<ProtocolDecl>(DC) &&
|
|
"Protocols cannot have missing stored properties");
|
|
|
|
return new (ctx) MissingMemberDecl(DC, name, numVTableEntries, hasStorage);
|
|
}
|
|
|
|
DeclName getFullName() const {
|
|
return Name;
|
|
}
|
|
|
|
unsigned getNumberOfVTableEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfVTableEntries;
|
|
}
|
|
|
|
unsigned getNumberOfFieldOffsetVectorEntries() const {
|
|
return Bits.MissingMemberDecl.NumberOfFieldOffsetVectorEntries;
|
|
}
|
|
|
|
SourceRange getSourceRange() const {
|
|
return SourceRange();
|
|
}
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::MissingMember;
|
|
}
|
|
};
|
|
|
|
inline bool AbstractStorageDecl::isSettable(const DeclContext *UseDC,
|
|
const DeclRefExpr *base) const {
|
|
if (auto vd = dyn_cast<VarDecl>(this))
|
|
return vd->isSettable(UseDC, base);
|
|
|
|
auto sd = cast<SubscriptDecl>(this);
|
|
return sd->supportsMutation();
|
|
}
|
|
|
|
inline void
|
|
AbstractStorageDecl::overwriteSetterAccess(AccessLevel accessLevel) {
|
|
Accessors.setInt(accessLevel);
|
|
if (auto setter = getAccessor(AccessorKind::Set))
|
|
setter->overwriteAccess(accessLevel);
|
|
if (auto modify = getAccessor(AccessorKind::Modify))
|
|
modify->overwriteAccess(accessLevel);
|
|
if (auto mutableAddressor = getAccessor(AccessorKind::MutableAddress))
|
|
mutableAddressor->overwriteAccess(accessLevel);
|
|
}
|
|
|
|
/// Constructors and destructors always have a 'self' parameter,
|
|
/// which is stored in an instance member. Functions only have a
|
|
/// 'self' if they are declared inside of a nominal type or extension,
|
|
/// in which case we tail-allocate storage for it.
|
|
inline ParamDecl **AbstractFunctionDecl::getImplicitSelfDeclStorage() {
|
|
switch (getKind()) {
|
|
default: llvm_unreachable("Unknown AbstractFunctionDecl!");
|
|
case DeclKind::Constructor:
|
|
return cast<ConstructorDecl>(this)->getImplicitSelfDeclStorage();
|
|
case DeclKind::Destructor:
|
|
return cast<DestructorDecl>(this)->getImplicitSelfDeclStorage();
|
|
case DeclKind::Func:
|
|
case DeclKind::Accessor:
|
|
return cast<FuncDecl>(this)->getImplicitSelfDeclStorage();
|
|
}
|
|
}
|
|
|
|
inline ParamDecl **FuncDecl::getImplicitSelfDeclStorage() {
|
|
if (!hasImplicitSelfDecl())
|
|
return nullptr;
|
|
|
|
if (!isa<AccessorDecl>(this)) {
|
|
assert(getKind() == DeclKind::Func && "no new kinds of functions");
|
|
return reinterpret_cast<ParamDecl **>(this+1);
|
|
}
|
|
return reinterpret_cast<ParamDecl **>(static_cast<AccessorDecl*>(this)+1);
|
|
}
|
|
|
|
inline DeclIterator &DeclIterator::operator++() {
|
|
Current = Current->NextDecl;
|
|
return *this;
|
|
}
|
|
|
|
inline bool AbstractFunctionDecl::hasForcedStaticDispatch() const {
|
|
if (auto func = dyn_cast<FuncDecl>(this))
|
|
return func->hasForcedStaticDispatch();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::isStatic() const {
|
|
// Currently, only storage and function decls can be static/class.
|
|
if (auto storage = dyn_cast<AbstractStorageDecl>(this))
|
|
return storage->isStatic();
|
|
if (auto func = dyn_cast<FuncDecl>(this))
|
|
return func->isStatic();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::isImportAsMember() const {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
|
|
return func->isImportAsMember();
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::hasCurriedSelf() const {
|
|
if (auto *afd = dyn_cast<AbstractFunctionDecl>(this))
|
|
return afd->hasImplicitSelfDecl();
|
|
if (isa<EnumElementDecl>(this))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
inline bool ValueDecl::hasParameterList() const {
|
|
if (auto *eed = dyn_cast<EnumElementDecl>(this))
|
|
return eed->hasAssociatedValues();
|
|
return isa<AbstractFunctionDecl>(this) || isa<SubscriptDecl>(this);
|
|
}
|
|
|
|
inline unsigned ValueDecl::getNumCurryLevels() const {
|
|
unsigned curryLevels = 0;
|
|
if (hasParameterList())
|
|
curryLevels++;
|
|
if (hasCurriedSelf())
|
|
curryLevels++;
|
|
return curryLevels;
|
|
}
|
|
|
|
inline bool Decl::isPotentiallyOverridable() const {
|
|
if (isa<VarDecl>(this) ||
|
|
isa<SubscriptDecl>(this) ||
|
|
isa<FuncDecl>(this) ||
|
|
isa<DestructorDecl>(this)) {
|
|
return getDeclContext()->getSelfClassDecl();
|
|
} 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::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;
|
|
}
|
|
|
|
/// Retrieve parameter declaration from the given source at given index.
|
|
const ParamDecl *getParameterAt(const ValueDecl *source, unsigned index);
|
|
|
|
/// Display Decl subclasses.
|
|
void simple_display(llvm::raw_ostream &out, const Decl *decl);
|
|
|
|
/// Display ValueDecl subclasses.
|
|
void simple_display(llvm::raw_ostream &out, const ValueDecl *decl);
|
|
|
|
/// Display ExtensionDecls.
|
|
inline void simple_display(llvm::raw_ostream &out, const ExtensionDecl *decl) {
|
|
simple_display(out, static_cast<const Decl *>(decl));
|
|
}
|
|
|
|
/// Display NominalTypeDecls.
|
|
inline void simple_display(llvm::raw_ostream &out,
|
|
const NominalTypeDecl *decl) {
|
|
simple_display(out, static_cast<const Decl *>(decl));
|
|
}
|
|
|
|
/// Display GenericContext.
|
|
///
|
|
/// The template keeps this sorted down in the overload set relative to the
|
|
/// more concrete overloads with Decl pointers thereby breaking a potential ambiguity.
|
|
template <typename T>
|
|
inline typename std::enable_if<std::is_same<T, GenericContext>::value>::type
|
|
simple_display(llvm::raw_ostream &out, const T *GC) {
|
|
simple_display(out, GC->getAsDecl());
|
|
}
|
|
|
|
/// Display GenericParamList.
|
|
void simple_display(llvm::raw_ostream &out, const GenericParamList *GPL);
|
|
|
|
/// Extract the source location from the given declaration.
|
|
SourceLoc extractNearestSourceLoc(const Decl *decl);
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const ExtensionDecl *ext) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(ext));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const GenericTypeDecl *type) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(type));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const NominalTypeDecl *type) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(type));
|
|
}
|
|
|
|
/// Extract the source location from the given declaration.
|
|
inline SourceLoc extractNearestSourceLoc(const AbstractFunctionDecl *func) {
|
|
return extractNearestSourceLoc(static_cast<const Decl *>(func));
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|