mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
The main idea here is that we really, really want to be able to recover the protocol requirement of a conformance reference even if it's abstract due to the conforming type being abstract (e.g. an archetype). I've made the conversion from ProtocolConformance* explicit to discourage casual contamination of the Ref with a null value. As part of this change, always make conformance arrays in Substitutions fully parallel to the requirements, as opposed to occasionally being empty when the conformances are abstract. As another part of this, I've tried to proactively fix prospective bugs with partially-concrete conformances, which I believe can happen with concretely-bound archetypes. In addition to just giving us stronger invariants, this is progress towards the removal of the archetype from Substitution.
4446 lines
148 KiB
C++
4446 lines
148 KiB
C++
//===--- Decl.cpp - Swift Language Decl ASTs ------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the Decl class and subclasses.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/ArchetypeBuilder.h"
|
|
#include "swift/AST/AST.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/ASTWalker.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/AST/DiagnosticsSema.h"
|
|
#include "swift/AST/Expr.h"
|
|
#include "swift/AST/ForeignErrorConvention.h"
|
|
#include "swift/AST/LazyResolver.h"
|
|
#include "swift/AST/Mangle.h"
|
|
#include "swift/AST/ParameterList.h"
|
|
#include "swift/AST/TypeLoc.h"
|
|
#include "clang/Lex/MacroInfo.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Basic/StringExtras.h"
|
|
#include "swift/Basic/Fallthrough.h"
|
|
|
|
#include "clang/Basic/CharInfo.h"
|
|
#include "clang/AST/DeclObjC.h"
|
|
|
|
#include <algorithm>
|
|
|
|
using namespace swift;
|
|
|
|
bool impl::isTestingEnabled(const ValueDecl *VD) {
|
|
return VD->getModuleContext()->isTestingEnabled();
|
|
}
|
|
|
|
clang::SourceLocation ClangNode::getLocation() const {
|
|
if (auto D = getAsDecl())
|
|
return D->getLocation();
|
|
if (auto M = getAsMacro())
|
|
return M->getDefinitionLoc();
|
|
|
|
return clang::SourceLocation();
|
|
}
|
|
|
|
clang::SourceRange ClangNode::getSourceRange() const {
|
|
if (auto D = getAsDecl())
|
|
return D->getSourceRange();
|
|
if (auto M = getAsMacro())
|
|
return clang::SourceRange(M->getDefinitionLoc(), M->getDefinitionEndLoc());
|
|
|
|
return clang::SourceLocation();
|
|
}
|
|
|
|
const clang::Module *ClangNode::getClangModule() const {
|
|
if (auto *M = getAsModule())
|
|
return M;
|
|
if (auto *ID = dyn_cast_or_null<clang::ImportDecl>(getAsDecl()))
|
|
return ID->getImportedModule();
|
|
return nullptr;
|
|
}
|
|
|
|
// Only allow allocation of Decls using the allocator in ASTContext.
|
|
void *Decl::operator new(size_t Bytes, const ASTContext &C,
|
|
unsigned Alignment) {
|
|
return C.Allocate(Bytes, Alignment);
|
|
}
|
|
|
|
// Only allow allocation of Modules using the allocator in ASTContext.
|
|
void *Module::operator new(size_t Bytes, const ASTContext &C,
|
|
unsigned Alignment) {
|
|
return C.Allocate(Bytes, Alignment);
|
|
}
|
|
|
|
StringRef Decl::getKindName(DeclKind K) {
|
|
switch (K) {
|
|
#define DECL(Id, Parent) case DeclKind::Id: return #Id;
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
llvm_unreachable("bad DeclKind");
|
|
}
|
|
|
|
DescriptiveDeclKind Decl::getDescriptiveKind() const {
|
|
#define TRIVIAL_KIND(Kind) \
|
|
case DeclKind::Kind: \
|
|
return DescriptiveDeclKind::Kind
|
|
|
|
switch (getKind()) {
|
|
TRIVIAL_KIND(Import);
|
|
TRIVIAL_KIND(Extension);
|
|
TRIVIAL_KIND(EnumCase);
|
|
TRIVIAL_KIND(TopLevelCode);
|
|
TRIVIAL_KIND(IfConfig);
|
|
TRIVIAL_KIND(PatternBinding);
|
|
TRIVIAL_KIND(InfixOperator);
|
|
TRIVIAL_KIND(PrefixOperator);
|
|
TRIVIAL_KIND(PostfixOperator);
|
|
TRIVIAL_KIND(TypeAlias);
|
|
TRIVIAL_KIND(GenericTypeParam);
|
|
TRIVIAL_KIND(AssociatedType);
|
|
TRIVIAL_KIND(Protocol);
|
|
TRIVIAL_KIND(Subscript);
|
|
TRIVIAL_KIND(Constructor);
|
|
TRIVIAL_KIND(Destructor);
|
|
TRIVIAL_KIND(EnumElement);
|
|
TRIVIAL_KIND(Param);
|
|
TRIVIAL_KIND(Module);
|
|
|
|
case DeclKind::Enum:
|
|
return cast<EnumDecl>(this)->getGenericParams()
|
|
? DescriptiveDeclKind::GenericEnum
|
|
: DescriptiveDeclKind::Enum;
|
|
|
|
case DeclKind::Struct:
|
|
return cast<StructDecl>(this)->getGenericParams()
|
|
? DescriptiveDeclKind::GenericStruct
|
|
: DescriptiveDeclKind::Struct;
|
|
|
|
case DeclKind::Class:
|
|
return cast<ClassDecl>(this)->getGenericParams()
|
|
? DescriptiveDeclKind::GenericClass
|
|
: DescriptiveDeclKind::Class;
|
|
|
|
case DeclKind::Var: {
|
|
auto var = cast<VarDecl>(this);
|
|
switch (var->getCorrectStaticSpelling()) {
|
|
case StaticSpellingKind::None:
|
|
return var->isLet()? DescriptiveDeclKind::Let
|
|
: DescriptiveDeclKind::Var;
|
|
case StaticSpellingKind::KeywordStatic:
|
|
return var->isLet()? DescriptiveDeclKind::StaticLet
|
|
: DescriptiveDeclKind::StaticVar;
|
|
case StaticSpellingKind::KeywordClass:
|
|
return var->isLet()? DescriptiveDeclKind::ClassLet
|
|
: DescriptiveDeclKind::ClassVar;
|
|
}
|
|
}
|
|
|
|
case DeclKind::Func: {
|
|
auto func = cast<FuncDecl>(this);
|
|
|
|
// First, check for an accessor.
|
|
switch (func->getAccessorKind()) {
|
|
case AccessorKind::NotAccessor:
|
|
// Other classifications below.
|
|
break;
|
|
|
|
case AccessorKind::IsGetter:
|
|
return DescriptiveDeclKind::Getter;
|
|
|
|
case AccessorKind::IsSetter:
|
|
return DescriptiveDeclKind::Setter;
|
|
|
|
case AccessorKind::IsWillSet:
|
|
return DescriptiveDeclKind::WillSet;
|
|
|
|
case AccessorKind::IsDidSet:
|
|
return DescriptiveDeclKind::DidSet;
|
|
|
|
case AccessorKind::IsAddressor:
|
|
return DescriptiveDeclKind::Addressor;
|
|
|
|
case AccessorKind::IsMutableAddressor:
|
|
return DescriptiveDeclKind::MutableAddressor;
|
|
|
|
case AccessorKind::IsMaterializeForSet:
|
|
return DescriptiveDeclKind::MaterializeForSet;
|
|
}
|
|
|
|
if (!func->getName().empty() && func->getName().isOperator())
|
|
return DescriptiveDeclKind::OperatorFunction;
|
|
|
|
if (func->getDeclContext()->isLocalContext())
|
|
return DescriptiveDeclKind::LocalFunction;
|
|
|
|
if (func->getDeclContext()->isModuleScopeContext())
|
|
return DescriptiveDeclKind::GlobalFunction;
|
|
|
|
// We have a method.
|
|
switch (func->getCorrectStaticSpelling()) {
|
|
case StaticSpellingKind::None:
|
|
return DescriptiveDeclKind::Method;
|
|
case StaticSpellingKind::KeywordStatic:
|
|
return DescriptiveDeclKind::StaticMethod;
|
|
case StaticSpellingKind::KeywordClass:
|
|
return DescriptiveDeclKind::ClassMethod;
|
|
}
|
|
}
|
|
}
|
|
#undef TRIVIAL_KIND
|
|
llvm_unreachable("bad DescriptiveDeclKind");
|
|
}
|
|
|
|
StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) {
|
|
#define ENTRY(Kind, String) case DescriptiveDeclKind::Kind: return String
|
|
switch (K) {
|
|
ENTRY(Import, "import");
|
|
ENTRY(Extension, "extension");
|
|
ENTRY(EnumCase, "case");
|
|
ENTRY(TopLevelCode, "top-level code");
|
|
ENTRY(IfConfig, "if configuration");
|
|
ENTRY(PatternBinding, "pattern binding");
|
|
ENTRY(Var, "var");
|
|
ENTRY(Param, "parameter");
|
|
ENTRY(Let, "let");
|
|
ENTRY(StaticVar, "static var");
|
|
ENTRY(StaticLet, "static let");
|
|
ENTRY(ClassVar, "class var");
|
|
ENTRY(ClassLet, "class let");
|
|
ENTRY(InfixOperator, "infix operator");
|
|
ENTRY(PrefixOperator, "prefix operator");
|
|
ENTRY(PostfixOperator, "postfix operator");
|
|
ENTRY(TypeAlias, "type alias");
|
|
ENTRY(GenericTypeParam, "generic parameter");
|
|
ENTRY(AssociatedType, "associated type");
|
|
ENTRY(Enum, "enum");
|
|
ENTRY(Struct, "struct");
|
|
ENTRY(Class, "class");
|
|
ENTRY(Protocol, "protocol");
|
|
ENTRY(GenericEnum, "generic enum");
|
|
ENTRY(GenericStruct, "generic struct");
|
|
ENTRY(GenericClass, "generic class");
|
|
ENTRY(Subscript, "subscript");
|
|
ENTRY(Constructor, "initializer");
|
|
ENTRY(Destructor, "deinitializer");
|
|
ENTRY(LocalFunction, "local function");
|
|
ENTRY(GlobalFunction, "global function");
|
|
ENTRY(OperatorFunction, "operator function");
|
|
ENTRY(Method, "instance method");
|
|
ENTRY(StaticMethod, "static method");
|
|
ENTRY(ClassMethod, "class method");
|
|
ENTRY(Getter, "getter");
|
|
ENTRY(Setter, "setter");
|
|
ENTRY(WillSet, "willSet observer");
|
|
ENTRY(DidSet, "didSet observer");
|
|
ENTRY(MaterializeForSet, "materializeForSet accessor");
|
|
ENTRY(Addressor, "address accessor");
|
|
ENTRY(MutableAddressor, "mutableAddress accessor");
|
|
ENTRY(EnumElement, "enum element");
|
|
ENTRY(Module, "module");
|
|
}
|
|
#undef ENTRY
|
|
llvm_unreachable("bad DescriptiveDeclKind");
|
|
}
|
|
|
|
llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS,
|
|
StaticSpellingKind SSK) {
|
|
switch (SSK) {
|
|
case StaticSpellingKind::None:
|
|
return OS << "<none>";
|
|
case StaticSpellingKind::KeywordStatic:
|
|
return OS << "'static'";
|
|
case StaticSpellingKind::KeywordClass:
|
|
return OS << "'class'";
|
|
}
|
|
llvm_unreachable("bad StaticSpellingKind");
|
|
}
|
|
|
|
DeclContext *Decl::getInnermostDeclContext() {
|
|
if (auto func = dyn_cast<AbstractFunctionDecl>(this))
|
|
return func;
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(this))
|
|
return nominal;
|
|
if (auto ext = dyn_cast<ExtensionDecl>(this))
|
|
return ext;
|
|
if (auto topLevel = dyn_cast<TopLevelCodeDecl>(this))
|
|
return topLevel;
|
|
|
|
return getDeclContext();
|
|
|
|
}
|
|
|
|
DeclContext *Decl::getDeclContextForModule() const {
|
|
if (auto module = dyn_cast<ModuleDecl>(this))
|
|
return const_cast<ModuleDecl *>(module);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void Decl::setDeclContext(DeclContext *DC) {
|
|
Context = DC;
|
|
}
|
|
|
|
bool Decl::isUserAccessible() const {
|
|
if (auto VD = dyn_cast<VarDecl>(this)){
|
|
return VD->isUserAccessible();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Module *Decl::getModuleContext() const {
|
|
return getDeclContext()->getParentModule();
|
|
}
|
|
|
|
// Helper functions to verify statically whether source-location
|
|
// functions have been overridden.
|
|
typedef const char (&TwoChars)[2];
|
|
template<typename Class>
|
|
inline char checkSourceLocType(SourceLoc (Class::*)() const);
|
|
inline TwoChars checkSourceLocType(SourceLoc (Decl::*)() const);
|
|
|
|
template<typename Class>
|
|
inline char checkSourceRangeType(SourceRange (Class::*)() const);
|
|
inline TwoChars checkSourceRangeType(SourceRange (Decl::*)() const);
|
|
|
|
SourceRange Decl::getSourceRange() const {
|
|
switch (getKind()) {
|
|
#define DECL(ID, PARENT) \
|
|
static_assert(sizeof(checkSourceRangeType(&ID##Decl::getSourceRange)) == 1, \
|
|
#ID "Decl is missing getSourceRange()"); \
|
|
case DeclKind::ID: return cast<ID##Decl>(this)->getSourceRange();
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
|
|
llvm_unreachable("Unknown decl kind");
|
|
}
|
|
|
|
SourceLoc Decl::getLoc() const {
|
|
switch (getKind()) {
|
|
#define DECL(ID, X) \
|
|
static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 1, \
|
|
#ID "Decl is missing getLoc()"); \
|
|
case DeclKind::ID: return cast<ID##Decl>(this)->getLoc();
|
|
#include "swift/AST/DeclNodes.def"
|
|
}
|
|
|
|
llvm_unreachable("Unknown decl kind");
|
|
}
|
|
|
|
bool Decl::isTransparent() const {
|
|
// Check if the declaration had the attribute.
|
|
if (getAttrs().hasAttribute<TransparentAttr>())
|
|
return true;
|
|
|
|
// Check if this is a function declaration which is within a transparent
|
|
// extension.
|
|
if (const AbstractFunctionDecl *FD = dyn_cast<AbstractFunctionDecl>(this)) {
|
|
if (const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(FD->getParent()))
|
|
if (ED->isTransparent())
|
|
return true;
|
|
}
|
|
|
|
// If this is an accessor, check if the transparent attribute was set
|
|
// on the value decl.
|
|
if (const FuncDecl *FD = dyn_cast<FuncDecl>(this)) {
|
|
if (auto *ASD = FD->getAccessorStorageDecl())
|
|
return ASD->isTransparent();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Decl::isBeingTypeChecked() {
|
|
auto decl = this;
|
|
while (true) {
|
|
if (decl->DeclBits.BeingTypeChecked)
|
|
return true;
|
|
|
|
auto dc = decl->getDeclContext();
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
|
|
decl = nominal;
|
|
else if (auto ext = dyn_cast<ExtensionDecl>(dc))
|
|
decl = ext;
|
|
else
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Decl::isPrivateStdlibDecl(bool whitelistProtocols) const {
|
|
const Decl *D = this;
|
|
if (auto ExtD = dyn_cast<ExtensionDecl>(D))
|
|
return ExtD->getExtendedType().isPrivateStdlibType(whitelistProtocols);
|
|
|
|
DeclContext *DC = D->getDeclContext()->getModuleScopeContext();
|
|
if (DC->getParentModule()->isBuiltinModule() ||
|
|
DC->getParentModule()->isSwiftShimsModule())
|
|
return true;
|
|
if (!DC->getParentModule()->isSystemModule())
|
|
return false;
|
|
auto FU = dyn_cast<FileUnit>(DC);
|
|
if (!FU)
|
|
return false;
|
|
// Check for Swift module and overlays.
|
|
if (!DC->getParentModule()->isStdlibModule() &&
|
|
FU->getKind() != FileUnitKind::SerializedAST)
|
|
return false;
|
|
|
|
auto hasInternalParameter = [](const ParameterList *params) -> bool {
|
|
for (auto param : *params) {
|
|
if (param->hasName() && param->getNameStr().startswith("_"))
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
if (auto AFD = dyn_cast<AbstractFunctionDecl>(D)) {
|
|
// Hide '~>' functions (but show the operator, because it defines
|
|
// precedence).
|
|
if (AFD->getNameStr() == "~>")
|
|
return true;
|
|
|
|
// If it's a function with a parameter with leading underscore, it's a
|
|
// private function.
|
|
for (auto *PL : AFD->getParameterLists())
|
|
if (hasInternalParameter(PL))
|
|
return true;
|
|
}
|
|
|
|
if (auto SubscriptD = dyn_cast<SubscriptDecl>(D)) {
|
|
if (hasInternalParameter(SubscriptD->getIndices()))
|
|
return true;
|
|
}
|
|
|
|
if (auto PD = dyn_cast<ProtocolDecl>(D)) {
|
|
StringRef NameStr = PD->getNameStr();
|
|
if (NameStr.startswith("_Builtin"))
|
|
return true;
|
|
if (NameStr.startswith("_") && NameStr.endswith("LiteralConvertible"))
|
|
return true;
|
|
if (whitelistProtocols)
|
|
return false;
|
|
}
|
|
|
|
if (auto ImportD = dyn_cast<ImportDecl>(D)) {
|
|
if (ImportD->getModule()->isSwiftShimsModule())
|
|
return true;
|
|
}
|
|
|
|
auto VD = dyn_cast<ValueDecl>(D);
|
|
if (!VD || !VD->hasName())
|
|
return false;
|
|
|
|
// If the name has leading underscore then it's a private symbol.
|
|
if (VD->getNameStr().startswith("_"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Decl::isWeakImported(Module *fromModule) const {
|
|
// For a Clang declaration, trust Clang.
|
|
if (auto clangDecl = getClangDecl()) {
|
|
return clangDecl->isWeakImported();
|
|
}
|
|
|
|
// FIXME: Implement using AvailableAttr::getMinVersionAvailability().
|
|
return false;
|
|
}
|
|
|
|
GenericParamList::GenericParamList(SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc WhereLoc,
|
|
MutableArrayRef<RequirementRepr> Requirements,
|
|
SourceLoc RAngleLoc)
|
|
: Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()),
|
|
WhereLoc(WhereLoc), Requirements(Requirements),
|
|
OuterParameters(nullptr),
|
|
FirstTrailingWhereArg(Requirements.size()),
|
|
Builder(nullptr)
|
|
{
|
|
std::uninitialized_copy(Params.begin(), Params.end(),
|
|
reinterpret_cast<GenericTypeParamDecl **>(this + 1));
|
|
}
|
|
|
|
GenericParamList *
|
|
GenericParamList::create(ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc RAngleLoc) {
|
|
unsigned Size = sizeof(GenericParamList)
|
|
+ sizeof(GenericTypeParamDecl *) * Params.size();
|
|
void *Mem = Context.Allocate(Size, alignof(GenericParamList));
|
|
return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(),
|
|
MutableArrayRef<RequirementRepr>(),
|
|
RAngleLoc);
|
|
}
|
|
|
|
GenericParamList *
|
|
GenericParamList::create(const ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericTypeParamDecl *> Params,
|
|
SourceLoc WhereLoc,
|
|
MutableArrayRef<RequirementRepr> Requirements,
|
|
SourceLoc RAngleLoc) {
|
|
unsigned Size = sizeof(GenericParamList)
|
|
+ sizeof(GenericTypeParamDecl *) * Params.size();
|
|
void *Mem = Context.Allocate(Size, alignof(GenericParamList));
|
|
return new (Mem) GenericParamList(LAngleLoc, Params,
|
|
WhereLoc,
|
|
Context.AllocateCopy(Requirements),
|
|
RAngleLoc);
|
|
}
|
|
|
|
void GenericParamList::addTrailingWhereClause(
|
|
ASTContext &ctx,
|
|
SourceLoc trailingWhereLoc,
|
|
ArrayRef<RequirementRepr> trailingRequirements) {
|
|
assert(TrailingWhereLoc.isInvalid() &&
|
|
"Already have a trailing where clause?");
|
|
TrailingWhereLoc = trailingWhereLoc;
|
|
FirstTrailingWhereArg = Requirements.size();
|
|
|
|
// Create a unified set of requirements.
|
|
auto newRequirements = ctx.AllocateUninitialized<RequirementRepr>(
|
|
Requirements.size() + trailingRequirements.size());
|
|
std::memcpy(newRequirements.data(), Requirements.data(),
|
|
Requirements.size() * sizeof(RequirementRepr));
|
|
std::memcpy(newRequirements.data() + Requirements.size(),
|
|
trailingRequirements.data(),
|
|
trailingRequirements.size() * sizeof(RequirementRepr));
|
|
|
|
Requirements = newRequirements;
|
|
}
|
|
|
|
GenericSignature *
|
|
GenericParamList::getAsCanonicalGenericSignature(
|
|
llvm::DenseMap<ArchetypeType *, Type> &archetypeMap,
|
|
ASTContext &C) const {
|
|
SmallVector<GenericTypeParamType *, 4> params;
|
|
SmallVector<Requirement, 4> requirements;
|
|
|
|
getAsGenericSignatureElements(C, archetypeMap, params, requirements);
|
|
|
|
// Canonicalize the types in the signature.
|
|
for (auto ¶m : params)
|
|
param = cast<GenericTypeParamType>(param->getCanonicalType());
|
|
|
|
for (auto &reqt : requirements)
|
|
reqt = Requirement(reqt.getKind(),
|
|
reqt.getFirstType()->getCanonicalType(),
|
|
reqt.getSecondType()->getCanonicalType());
|
|
|
|
return GenericSignature::get(params, requirements, /*isKnownCanonical=*/true);
|
|
}
|
|
|
|
ArrayRef<Substitution>
|
|
GenericParamList::getForwardingSubstitutions(ASTContext &C) {
|
|
SmallVector<Substitution, 4> subs;
|
|
|
|
// TODO: IRGen wants substitutions for secondary archetypes.
|
|
// for (auto ¶m : params->getNestedGenericParams()) {
|
|
// ArchetypeType *archetype = param.getAsTypeParam()->getArchetype();
|
|
|
|
for (auto archetype : getAllNestedArchetypes()) {
|
|
// "Check conformance" on each declared protocol to build a
|
|
// conformance map.
|
|
SmallVector<ProtocolConformanceRef, 2> conformances;
|
|
|
|
for (ProtocolDecl *proto : archetype->getConformsTo()) {
|
|
conformances.push_back(ProtocolConformanceRef(proto));
|
|
}
|
|
|
|
// Build an identity mapping with the derived conformances.
|
|
auto replacement = SubstitutedType::get(archetype, archetype, C);
|
|
subs.push_back({archetype, replacement, C.AllocateCopy(conformances)});
|
|
}
|
|
|
|
return C.AllocateCopy(subs);
|
|
}
|
|
|
|
// Helper for getAsGenericSignatureElements to remap an archetype in a
|
|
// requirement to a canonical dependent type.
|
|
Type
|
|
ArchetypeType::getAsDependentType(
|
|
const llvm::DenseMap<ArchetypeType*, Type> &archetypeMap) {
|
|
// Map associated archetypes to DependentMemberTypes.
|
|
if (auto parent = getParent()) {
|
|
auto assocTy = getAssocType();
|
|
assert(assocTy);
|
|
Type base = parent->getAsDependentType(archetypeMap);
|
|
return DependentMemberType::get(base, assocTy, getASTContext());
|
|
}
|
|
// Map primary archetypes to generic type parameters.
|
|
auto found = archetypeMap.find(this);
|
|
assert(found != archetypeMap.end()
|
|
&& "did not find generic param for archetype");
|
|
return found->second;
|
|
}
|
|
|
|
static Type getAsDependentType(Type t,
|
|
const llvm::DenseMap<ArchetypeType*, Type> &archetypeMap) {
|
|
if (!t->hasArchetype())
|
|
return t;
|
|
|
|
return t.transform([&](Type type) -> Type {
|
|
if (auto arch = type->getAs<ArchetypeType>())
|
|
return arch->getAsDependentType(archetypeMap);
|
|
return type;
|
|
});
|
|
}
|
|
|
|
// A helper to recursively collect the generic parameters from the outer levels
|
|
// of a generic parameter list.
|
|
void
|
|
GenericParamList::getAsGenericSignatureElements(ASTContext &C,
|
|
llvm::DenseMap<ArchetypeType *, Type> &archetypeMap,
|
|
SmallVectorImpl<GenericTypeParamType *> &genericParams,
|
|
SmallVectorImpl<Requirement> &requirements) const {
|
|
// Collect outer generic parameters first.
|
|
if (OuterParameters) {
|
|
OuterParameters->getAsGenericSignatureElements(C, archetypeMap,
|
|
genericParams,
|
|
requirements);
|
|
}
|
|
|
|
// Collect our parameters.
|
|
for (auto paramIndex : indices(getParams())) {
|
|
auto param = getParams()[paramIndex];
|
|
|
|
auto typeParamTy = param->getDeclaredType()->castTo<GenericTypeParamType>();
|
|
|
|
// Make sure we didn't visit this param already in the parent.
|
|
auto found = archetypeMap.find(param->getArchetype());
|
|
if (found != archetypeMap.end()) {
|
|
assert(found->second->isEqual(typeParamTy));
|
|
continue;
|
|
}
|
|
|
|
// Set up a mapping we can use to remap requirements to dependent types.
|
|
ArchetypeType *archetype = getPrimaryArchetypes()[paramIndex];
|
|
archetypeMap[archetype] = typeParamTy;
|
|
|
|
genericParams.push_back(typeParamTy);
|
|
requirements.push_back(Requirement(RequirementKind::WitnessMarker,
|
|
typeParamTy, typeParamTy));
|
|
|
|
// Collect conformance requirements declared on the archetype.
|
|
if (auto super = archetype->getSuperclass()) {
|
|
requirements.push_back(Requirement(RequirementKind::Conformance,
|
|
typeParamTy, super));
|
|
}
|
|
for (auto proto : archetype->getConformsTo()) {
|
|
requirements.push_back(Requirement(RequirementKind::Conformance,
|
|
typeParamTy, proto->getDeclaredType()));
|
|
}
|
|
}
|
|
|
|
// FIXME: Emit WitnessMarker requirements for associated types in an order
|
|
// that preserves AllArchetypes order but otherwise makes no sense.
|
|
for (auto assocTy : getAssociatedArchetypes()) {
|
|
auto depTy = getAsDependentType(assocTy, archetypeMap);
|
|
requirements.push_back(Requirement(RequirementKind::WitnessMarker,
|
|
depTy, depTy));
|
|
|
|
// Add conformance requirements for this associated archetype.
|
|
for (const auto &repr : getRequirements()) {
|
|
// Handle same-type requirements at last.
|
|
if (repr.getKind() != RequirementKind::Conformance)
|
|
continue;
|
|
|
|
// Primary conformance declarations would have already been gathered as
|
|
// conformance requirements of the archetype.
|
|
if (auto arch = repr.getSubject()->getAs<ArchetypeType>())
|
|
if (!arch->getParent())
|
|
continue;
|
|
|
|
auto depTyOfReqt = getAsDependentType(repr.getSubject(), archetypeMap);
|
|
if (depTyOfReqt.getPointer() != depTy.getPointer())
|
|
continue;
|
|
|
|
Requirement reqt(RequirementKind::Conformance,
|
|
getAsDependentType(repr.getSubject(), archetypeMap),
|
|
getAsDependentType(repr.getConstraint(), archetypeMap));
|
|
requirements.push_back(reqt);
|
|
}
|
|
}
|
|
|
|
// Add all of the same-type requirements.
|
|
if (Builder) {
|
|
for (auto req : Builder->getSameTypeRequirements()) {
|
|
auto firstType = req.first->getDependentType(*Builder, false);
|
|
Type secondType;
|
|
if (auto concrete = req.second.dyn_cast<Type>())
|
|
secondType = getAsDependentType(concrete, archetypeMap);
|
|
else if (auto secondPA =
|
|
req.second.dyn_cast<ArchetypeBuilder::PotentialArchetype*>())
|
|
secondType = secondPA->getDependentType(*Builder, false);
|
|
|
|
if (firstType->is<ErrorType>() || secondType->is<ErrorType>())
|
|
continue;
|
|
|
|
requirements.push_back(Requirement(RequirementKind::SameType,
|
|
firstType, secondType));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// \brief Add the nested archetypes of the given archetype to the set
|
|
/// of all archetypes.
|
|
void GenericParamList::addNestedArchetypes(ArchetypeType *archetype,
|
|
SmallPtrSetImpl<ArchetypeType*> &known,
|
|
SmallVectorImpl<ArchetypeType*> &all) {
|
|
for (auto nested : archetype->getNestedTypes()) {
|
|
auto nestedArch = nested.second.getAsArchetype();
|
|
if (!nestedArch)
|
|
continue;
|
|
if (known.insert(nestedArch).second) {
|
|
assert(!nestedArch->isPrimary() && "Unexpected primary archetype");
|
|
all.push_back(nestedArch);
|
|
addNestedArchetypes(nestedArch, known, all);
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayRef<ArchetypeType*>
|
|
GenericParamList::deriveAllArchetypes(ArrayRef<GenericTypeParamDecl *> params,
|
|
SmallVectorImpl<ArchetypeType*> &all) {
|
|
// This should be kept in sync with ArchetypeBuilder::getAllArchetypes().
|
|
|
|
assert(all.empty());
|
|
llvm::SmallPtrSet<ArchetypeType*, 8> known;
|
|
|
|
// Collect all the primary archetypes.
|
|
for (auto param : params) {
|
|
auto archetype = param->getArchetype();
|
|
if (known.insert(archetype).second)
|
|
all.push_back(archetype);
|
|
}
|
|
|
|
// Collect all the nested archetypes.
|
|
for (auto param : params) {
|
|
auto archetype = param->getArchetype();
|
|
addNestedArchetypes(archetype, known, all);
|
|
}
|
|
|
|
return all;
|
|
}
|
|
|
|
TrailingWhereClause::TrailingWhereClause(
|
|
SourceLoc whereLoc,
|
|
ArrayRef<RequirementRepr> requirements)
|
|
: WhereLoc(whereLoc),
|
|
NumRequirements(requirements.size())
|
|
{
|
|
memcpy(getRequirements().data(), requirements.data(),
|
|
NumRequirements * sizeof(RequirementRepr));
|
|
}
|
|
|
|
TrailingWhereClause *TrailingWhereClause::create(
|
|
ASTContext &ctx,
|
|
SourceLoc whereLoc,
|
|
ArrayRef<RequirementRepr> requirements) {
|
|
unsigned size = sizeof(TrailingWhereClause)
|
|
+ requirements.size() * sizeof(RequirementRepr);
|
|
void *mem = ctx.Allocate(size, alignof(TrailingWhereClause));
|
|
return new (mem) TrailingWhereClause(whereLoc, requirements);
|
|
}
|
|
|
|
ImportDecl *ImportDecl::create(ASTContext &Ctx, DeclContext *DC,
|
|
SourceLoc ImportLoc, ImportKind Kind,
|
|
SourceLoc KindLoc,
|
|
ArrayRef<AccessPathElement> Path,
|
|
ClangNode ClangN) {
|
|
assert(!Path.empty());
|
|
assert(Kind == ImportKind::Module || Path.size() > 1);
|
|
assert(ClangN.isNull() || ClangN.getAsModule() ||
|
|
isa<clang::ImportDecl>(ClangN.getAsDecl()));
|
|
size_t Size = sizeof(ImportDecl) + Path.size() * sizeof(AccessPathElement);
|
|
void *ptr = allocateMemoryForDecl<ImportDecl>(Ctx, Size, !ClangN.isNull());
|
|
auto D = new (ptr) ImportDecl(DC, ImportLoc, Kind, KindLoc, Path);
|
|
if (ClangN)
|
|
D->setClangNode(ClangN);
|
|
return D;
|
|
}
|
|
|
|
ImportDecl::ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
|
|
SourceLoc KindLoc, ArrayRef<AccessPathElement> Path)
|
|
: Decl(DeclKind::Import, DC), ImportLoc(ImportLoc), KindLoc(KindLoc),
|
|
NumPathElements(Path.size()) {
|
|
ImportDeclBits.ImportKind = static_cast<unsigned>(K);
|
|
assert(getImportKind() == K && "not enough bits for ImportKind");
|
|
std::uninitialized_copy(Path.begin(), Path.end(), getPathBuffer());
|
|
}
|
|
|
|
ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) {
|
|
switch (VD->getKind()) {
|
|
case DeclKind::Import:
|
|
case DeclKind::Extension:
|
|
case DeclKind::PatternBinding:
|
|
case DeclKind::TopLevelCode:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
case DeclKind::EnumCase:
|
|
case DeclKind::IfConfig:
|
|
llvm_unreachable("not a ValueDecl");
|
|
|
|
case DeclKind::AssociatedType:
|
|
case DeclKind::Constructor:
|
|
case DeclKind::Destructor:
|
|
case DeclKind::GenericTypeParam:
|
|
case DeclKind::Subscript:
|
|
case DeclKind::EnumElement:
|
|
case DeclKind::Param:
|
|
llvm_unreachable("not a top-level ValueDecl");
|
|
|
|
case DeclKind::Protocol:
|
|
return ImportKind::Protocol;
|
|
|
|
case DeclKind::Class:
|
|
return ImportKind::Class;
|
|
case DeclKind::Enum:
|
|
return ImportKind::Enum;
|
|
case DeclKind::Struct:
|
|
return ImportKind::Struct;
|
|
|
|
case DeclKind::TypeAlias: {
|
|
Type underlyingTy = cast<TypeAliasDecl>(VD)->getUnderlyingType();
|
|
return getBestImportKind(underlyingTy->getAnyNominal());
|
|
}
|
|
|
|
case DeclKind::Func:
|
|
return ImportKind::Func;
|
|
|
|
case DeclKind::Var:
|
|
return ImportKind::Var;
|
|
|
|
case DeclKind::Module:
|
|
return ImportKind::Module;
|
|
}
|
|
llvm_unreachable("bad DeclKind");
|
|
}
|
|
|
|
Optional<ImportKind>
|
|
ImportDecl::findBestImportKind(ArrayRef<ValueDecl *> Decls) {
|
|
assert(!Decls.empty());
|
|
ImportKind FirstKind = ImportDecl::getBestImportKind(Decls.front());
|
|
|
|
// FIXME: Only functions can be overloaded.
|
|
if (Decls.size() == 1)
|
|
return FirstKind;
|
|
if (FirstKind != ImportKind::Func)
|
|
return None;
|
|
|
|
for (auto NextDecl : Decls.slice(1)) {
|
|
if (ImportDecl::getBestImportKind(NextDecl) != FirstKind)
|
|
return None;
|
|
}
|
|
|
|
return FirstKind;
|
|
}
|
|
|
|
template <typename T>
|
|
static void
|
|
loadAllConformances(const T *container,
|
|
const LazyLoaderArray<ProtocolConformance*> &loaderInfo) {
|
|
if (!loaderInfo.isLazy())
|
|
return;
|
|
|
|
// Don't try to load conformances re-entrant-ly.
|
|
auto resolver = loaderInfo.getLoader();
|
|
auto contextData = loaderInfo.getLoaderContextData();
|
|
const_cast<LazyLoaderArray<ProtocolConformance*> &>(loaderInfo) = {};
|
|
|
|
SmallVector<ProtocolConformance *, 8> Conformances;
|
|
resolver->loadAllConformances(container, contextData, Conformances);
|
|
const_cast<T *>(container)->setConformances(
|
|
container->getASTContext().AllocateCopy(Conformances));
|
|
}
|
|
|
|
DeclRange NominalTypeDecl::getMembers(bool forceDelayedMembers) const {
|
|
loadAllMembers();
|
|
if (forceDelayedMembers)
|
|
const_cast<NominalTypeDecl*>(this)->forceDelayedMemberDecls();
|
|
return IterableDeclContext::getMembers();
|
|
}
|
|
|
|
void NominalTypeDecl::setMemberLoader(LazyMemberLoader *resolver,
|
|
uint64_t contextData) {
|
|
IterableDeclContext::setLoader(resolver, contextData);
|
|
}
|
|
|
|
void NominalTypeDecl::setConformanceLoader(LazyMemberLoader *resolver,
|
|
uint64_t contextData) {
|
|
assert(!HaveConformanceLoader &&
|
|
"Already have a conformance loader");
|
|
HaveConformanceLoader = true;
|
|
getASTContext().recordConformanceLoader(this, resolver, contextData);
|
|
}
|
|
|
|
std::pair<LazyMemberLoader *, uint64_t>
|
|
NominalTypeDecl::takeConformanceLoaderSlow() {
|
|
assert(HaveConformanceLoader && "no conformance loader?");
|
|
HaveConformanceLoader = false;
|
|
return getASTContext().takeConformanceLoader(this);
|
|
}
|
|
|
|
ExtensionDecl::ExtensionDecl(SourceLoc extensionLoc,
|
|
TypeLoc extendedType,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause)
|
|
: Decl(DeclKind::Extension, parent),
|
|
DeclContext(DeclContextKind::ExtensionDecl, parent),
|
|
IterableDeclContext(IterableDeclContextKind::ExtensionDecl),
|
|
ExtensionLoc(extensionLoc),
|
|
ExtendedType(extendedType),
|
|
Inherited(inherited),
|
|
TrailingWhere(trailingWhereClause)
|
|
{
|
|
ExtensionDeclBits.Validated = false;
|
|
ExtensionDeclBits.CheckedInheritanceClause = false;
|
|
ExtensionDeclBits.DefaultAndMaxAccessLevel = 0;
|
|
ExtensionDeclBits.HaveConformanceLoader = false;
|
|
}
|
|
|
|
ExtensionDecl *ExtensionDecl::create(ASTContext &ctx, SourceLoc extensionLoc,
|
|
TypeLoc extendedType,
|
|
MutableArrayRef<TypeLoc> inherited,
|
|
DeclContext *parent,
|
|
TrailingWhereClause *trailingWhereClause,
|
|
ClangNode clangNode) {
|
|
unsigned size = sizeof(ExtensionDecl);
|
|
|
|
void *declPtr = allocateMemoryForDecl<ExtensionDecl>(ctx, size,
|
|
!clangNode.isNull());
|
|
|
|
// Construct the extension.
|
|
auto result = ::new (declPtr) ExtensionDecl(extensionLoc, extendedType,
|
|
inherited, parent,
|
|
trailingWhereClause);
|
|
if (clangNode)
|
|
result->setClangNode(clangNode);
|
|
|
|
return result;
|
|
}
|
|
|
|
void ExtensionDecl::setGenericParams(GenericParamList *params) {
|
|
GenericParams = params;
|
|
|
|
if (GenericParams) {
|
|
for (auto param : *GenericParams)
|
|
param->setDeclContext(this);
|
|
}
|
|
}
|
|
|
|
void ExtensionDecl::setGenericSignature(GenericSignature *sig) {
|
|
assert(!GenericSig && "Already have generic signature");
|
|
GenericSig = sig;
|
|
}
|
|
|
|
DeclRange ExtensionDecl::getMembers(bool forceDelayedMembers) const {
|
|
loadAllMembers();
|
|
return IterableDeclContext::getMembers();
|
|
}
|
|
|
|
void ExtensionDecl::setMemberLoader(LazyMemberLoader *resolver,
|
|
uint64_t contextData) {
|
|
IterableDeclContext::setLoader(resolver, contextData);
|
|
}
|
|
|
|
void ExtensionDecl::setConformanceLoader(LazyMemberLoader *resolver,
|
|
uint64_t contextData) {
|
|
assert(!ExtensionDeclBits.HaveConformanceLoader &&
|
|
"Already have a conformance loader");
|
|
ExtensionDeclBits.HaveConformanceLoader = true;
|
|
getASTContext().recordConformanceLoader(this, resolver, contextData);
|
|
}
|
|
|
|
std::pair<LazyMemberLoader *, uint64_t>
|
|
ExtensionDecl::takeConformanceLoaderSlow() {
|
|
assert(ExtensionDeclBits.HaveConformanceLoader && "no conformance loader?");
|
|
ExtensionDeclBits.HaveConformanceLoader = false;
|
|
return getASTContext().takeConformanceLoader(this);
|
|
}
|
|
|
|
bool ExtensionDecl::isConstrainedExtension() const {
|
|
auto nominal = getExtendedType()->getAnyNominal();
|
|
|
|
// Error case: erroneous extension.
|
|
if (!nominal)
|
|
return false;
|
|
|
|
// Non-generic extension.
|
|
if (!getGenericSignature())
|
|
return false;
|
|
|
|
// If the generic signature differs from that of the nominal type, it's a
|
|
// constrained extension.
|
|
return getGenericSignature()->getCanonicalSignature()
|
|
!= nominal->getGenericSignature()->getCanonicalSignature();
|
|
}
|
|
|
|
|
|
PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
unsigned NumPatternEntries,
|
|
DeclContext *Parent)
|
|
: Decl(DeclKind::PatternBinding, Parent),
|
|
StaticLoc(StaticLoc), VarLoc(VarLoc),
|
|
numPatternEntries(NumPatternEntries) {
|
|
PatternBindingDeclBits.IsStatic = StaticLoc.isValid();
|
|
PatternBindingDeclBits.StaticSpelling =
|
|
static_cast<unsigned>(StaticSpelling);
|
|
}
|
|
|
|
PatternBindingDecl *
|
|
PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc VarLoc,
|
|
ArrayRef<PatternBindingEntry> PatternList,
|
|
DeclContext *Parent) {
|
|
size_t Size = sizeof(PatternBindingDecl) +
|
|
PatternList.size() * sizeof(PatternBindingEntry);
|
|
void *D = allocateMemoryForDecl<PatternBindingDecl>(Ctx, Size,
|
|
false);
|
|
auto PBD = ::new (D) PatternBindingDecl(StaticLoc, StaticSpelling, VarLoc,
|
|
PatternList.size(), Parent);
|
|
|
|
// Set up the patterns.
|
|
auto entries = PBD->getMutablePatternList();
|
|
unsigned elt = 0U-1;
|
|
for (auto pe : PatternList) {
|
|
++elt;
|
|
auto &newEntry = entries[elt];
|
|
newEntry = { nullptr, pe.getInit() };
|
|
PBD->setPattern(elt, pe.getPattern());
|
|
}
|
|
return PBD;
|
|
}
|
|
|
|
static bool patternContainsVarDeclBinding(const Pattern *P, const VarDecl *VD) {
|
|
bool Result = false;
|
|
P->forEachVariable([&](VarDecl *FoundVD) {
|
|
Result |= FoundVD == VD;
|
|
});
|
|
return Result;
|
|
}
|
|
|
|
unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) const {
|
|
assert(VD && "Cannot find a null VarDecl");
|
|
|
|
auto List = getPatternList();
|
|
if (List.size() == 1) {
|
|
assert(patternContainsVarDeclBinding(List[0].getPattern(), VD) &&
|
|
"Single entry PatternBindingDecl is set up wrong");
|
|
return 0;
|
|
}
|
|
|
|
unsigned Result = 0;
|
|
for (auto entry : List) {
|
|
if (patternContainsVarDeclBinding(entry.getPattern(), VD))
|
|
return Result;
|
|
++Result;
|
|
}
|
|
|
|
assert(0 && "PatternBindingDecl doesn't bind the specified VarDecl!");
|
|
return ~0U;
|
|
}
|
|
|
|
|
|
SourceRange PatternBindingDecl::getSourceRange() const {
|
|
SourceLoc startLoc = getStartLoc();
|
|
|
|
// Take the init of the last pattern in the list.
|
|
if (auto init = getPatternList().back().getInit()) {
|
|
SourceLoc EndLoc = init->getEndLoc();
|
|
if (EndLoc.isValid())
|
|
return { startLoc, EndLoc };
|
|
}
|
|
// If the last pattern had no init, we take the end of its pattern.
|
|
return { startLoc, getPatternList().back().getPattern()->getEndLoc() };
|
|
}
|
|
|
|
static StaticSpellingKind getCorrectStaticSpellingForDecl(const Decl *D) {
|
|
auto StaticSpelling = StaticSpellingKind::KeywordStatic;
|
|
if (Type T = D->getDeclContext()->getDeclaredTypeInContext()) {
|
|
if (auto NTD = T->getAnyNominal()) {
|
|
if (isa<ClassDecl>(NTD))
|
|
StaticSpelling = StaticSpellingKind::KeywordClass;
|
|
}
|
|
}
|
|
return StaticSpelling;
|
|
}
|
|
|
|
StaticSpellingKind PatternBindingDecl::getCorrectStaticSpelling() const {
|
|
if (!isStatic())
|
|
return StaticSpellingKind::None;
|
|
|
|
return getCorrectStaticSpellingForDecl(this);
|
|
}
|
|
|
|
|
|
bool PatternBindingDecl::hasStorage() const {
|
|
// Walk the pattern, to check to see if any of the VarDecls included in it
|
|
// have storage.
|
|
bool HasStorage = false;
|
|
for (auto entry : getPatternList())
|
|
entry.getPattern()->forEachVariable([&](VarDecl *VD) {
|
|
if (VD->hasStorage())
|
|
HasStorage = true;
|
|
});
|
|
|
|
return HasStorage;
|
|
}
|
|
|
|
void PatternBindingDecl::setPattern(unsigned i, Pattern *P) {
|
|
auto PatternList = getMutablePatternList();
|
|
PatternList[i].setPattern(P);
|
|
|
|
// Make sure that any VarDecl's contained within the pattern know about this
|
|
// PatternBindingDecl as their parent.
|
|
if (P)
|
|
P->forEachVariable([&](VarDecl *VD) {
|
|
VD->setParentPatternBinding(this);
|
|
});
|
|
}
|
|
|
|
|
|
VarDecl *PatternBindingDecl::getSingleVar() const {
|
|
if (getNumPatternEntries() == 1)
|
|
return getPatternList()[0].getPattern()->getSingleVar();
|
|
return nullptr;
|
|
}
|
|
|
|
SourceLoc TopLevelCodeDecl::getStartLoc() const {
|
|
return Body->getStartLoc();
|
|
}
|
|
|
|
SourceRange TopLevelCodeDecl::getSourceRange() const {
|
|
return Body->getSourceRange();
|
|
}
|
|
|
|
SourceRange IfConfigDecl::getSourceRange() const {
|
|
return SourceRange(getLoc(), EndLoc);
|
|
}
|
|
|
|
static bool isPolymorphic(const AbstractStorageDecl *storage) {
|
|
auto ctx = storage->getDeclContext()->getDeclaredTypeInContext();
|
|
if (!ctx) return false;
|
|
|
|
auto nominal = ctx->getNominalOrBoundGenericNominal();
|
|
assert(nominal && "context wasn't a nominal type?");
|
|
switch (nominal->getKind()) {
|
|
#define DECL(ID, BASE) case DeclKind::ID:
|
|
#define NOMINAL_TYPE_DECL(ID, BASE)
|
|
#include "swift/AST/DeclNodes.def"
|
|
llvm_unreachable("not a nominal type!");
|
|
|
|
case DeclKind::Struct:
|
|
case DeclKind::Enum:
|
|
return false;
|
|
|
|
case DeclKind::Protocol:
|
|
return true;
|
|
|
|
case DeclKind::Class:
|
|
// Final properties can always be direct, even in classes.
|
|
return !storage->isFinal();
|
|
}
|
|
llvm_unreachable("bad DeclKind");
|
|
}
|
|
|
|
/// Determines the access semantics to use in a DeclRefExpr or
|
|
/// MemberRefExpr use of this value in the specified context.
|
|
AccessSemantics
|
|
ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC) const {
|
|
if (auto *var = dyn_cast<AbstractStorageDecl>(this)) {
|
|
// Observing member are accessed directly from within their didSet/willSet
|
|
// specifiers. This prevents assignments from becoming infinite loops.
|
|
if (auto *UseFD = dyn_cast<FuncDecl>(UseDC))
|
|
if (var->hasStorage() && var->hasAccessorFunctions() &&
|
|
UseFD->getAccessorStorageDecl() == var)
|
|
return AccessSemantics::DirectToStorage;
|
|
|
|
// "StoredWithTrivialAccessors" are generally always accessed indirectly,
|
|
// but if we know that the trivial accessor will always produce the same
|
|
// thing as the getter/setter (i.e., it can't be overridden), then just do a
|
|
// direct access.
|
|
//
|
|
// This is true in structs and for final properties.
|
|
// TODO: What about static properties?
|
|
switch (var->getStorageKind()) {
|
|
case AbstractStorageDecl::Stored:
|
|
case AbstractStorageDecl::Addressed:
|
|
// The storage is completely trivial. Always do direct access.
|
|
return AccessSemantics::DirectToStorage;
|
|
|
|
case AbstractStorageDecl::StoredWithTrivialAccessors:
|
|
case AbstractStorageDecl::AddressedWithTrivialAccessors: {
|
|
// If the property is defined in a non-final class or a protocol, the
|
|
// accessors are dynamically dispatched, and we cannot do direct access.
|
|
if (isPolymorphic(var))
|
|
return AccessSemantics::Ordinary;
|
|
|
|
// If the property is defined in a nominal type which must be accessed
|
|
// resiliently from the current module, we cannot do direct access.
|
|
auto VarDC = var->getDeclContext();
|
|
if (auto *nominal = VarDC->isNominalTypeOrNominalTypeExtensionContext())
|
|
if (!nominal->hasFixedLayout(UseDC->getParentModule()))
|
|
return AccessSemantics::Ordinary;
|
|
|
|
// We know enough about the property to perform direct access.
|
|
return AccessSemantics::DirectToStorage;
|
|
}
|
|
|
|
case AbstractStorageDecl::StoredWithObservers:
|
|
case AbstractStorageDecl::InheritedWithObservers:
|
|
case AbstractStorageDecl::Computed:
|
|
case AbstractStorageDecl::ComputedWithMutableAddress:
|
|
case AbstractStorageDecl::AddressedWithObservers:
|
|
// Property is not trivially backed by storage, do not perform
|
|
// direct access.
|
|
break;
|
|
}
|
|
}
|
|
|
|
return AccessSemantics::Ordinary;
|
|
}
|
|
|
|
AccessStrategy
|
|
AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics,
|
|
AccessKind accessKind) const {
|
|
switch (semantics) {
|
|
case AccessSemantics::DirectToStorage:
|
|
switch (getStorageKind()) {
|
|
case Stored:
|
|
case StoredWithTrivialAccessors:
|
|
case StoredWithObservers:
|
|
return AccessStrategy::Storage;
|
|
|
|
case Addressed:
|
|
case AddressedWithTrivialAccessors:
|
|
case AddressedWithObservers:
|
|
case ComputedWithMutableAddress:
|
|
return AccessStrategy::Addressor;
|
|
|
|
case InheritedWithObservers:
|
|
case Computed:
|
|
llvm_unreachable("cannot have direct-to-storage access to "
|
|
"computed storage");
|
|
}
|
|
llvm_unreachable("bad storage kind");
|
|
|
|
case AccessSemantics::DirectToAccessor:
|
|
assert(hasAccessorFunctions() &&
|
|
"direct-to-accessors access to storage without accessors?");
|
|
return AccessStrategy::DirectToAccessor;
|
|
|
|
case AccessSemantics::Ordinary:
|
|
switch (auto storageKind = getStorageKind()) {
|
|
case Stored:
|
|
return AccessStrategy::Storage;
|
|
case Addressed:
|
|
return AccessStrategy::Addressor;
|
|
|
|
case StoredWithObservers:
|
|
case InheritedWithObservers:
|
|
case AddressedWithObservers:
|
|
// An observing property backed by its own storage (i.e. which
|
|
// doesn't override anything) has a trivial getter implementation,
|
|
// but its setter is interesting.
|
|
if (accessKind != AccessKind::Read ||
|
|
storageKind == InheritedWithObservers) {
|
|
if (isPolymorphic(this))
|
|
return AccessStrategy::DispatchToAccessor;
|
|
return AccessStrategy::DirectToAccessor;
|
|
}
|
|
|
|
// Fall through to the trivial-implementation case.
|
|
SWIFT_FALLTHROUGH;
|
|
|
|
case StoredWithTrivialAccessors:
|
|
case AddressedWithTrivialAccessors: {
|
|
// If the property is defined in a non-final class or a protocol, the
|
|
// accessors are dynamically dispatched, and we cannot do direct access.
|
|
if (isPolymorphic(this))
|
|
return AccessStrategy::DispatchToAccessor;
|
|
|
|
// If we end up here with a stored property of a type that's resilient
|
|
// from some resilience domain, we cannot do direct access.
|
|
//
|
|
// As an optimization, we do want to perform direct accesses of stored
|
|
// properties of resilient types in the same resilience domain as the
|
|
// access.
|
|
//
|
|
// This is done by using DirectToStorage semantics above, with the
|
|
// understanding that the access semantics are with respect to the
|
|
// resilience domain of the accessor's caller.
|
|
auto DC = getDeclContext();
|
|
if (auto *nominal = DC->isNominalTypeOrNominalTypeExtensionContext())
|
|
if (!nominal->hasFixedLayout())
|
|
return AccessStrategy::DirectToAccessor;
|
|
|
|
if (storageKind == StoredWithObservers ||
|
|
storageKind == StoredWithTrivialAccessors) {
|
|
return AccessStrategy::Storage;
|
|
} else {
|
|
assert(storageKind == AddressedWithObservers ||
|
|
storageKind == AddressedWithTrivialAccessors);
|
|
return AccessStrategy::Addressor;
|
|
}
|
|
}
|
|
|
|
case ComputedWithMutableAddress:
|
|
if (isPolymorphic(this))
|
|
return AccessStrategy::DispatchToAccessor;
|
|
if (accessKind == AccessKind::Read)
|
|
return AccessStrategy::DirectToAccessor;
|
|
return AccessStrategy::Addressor;
|
|
|
|
case Computed:
|
|
if (isPolymorphic(this))
|
|
return AccessStrategy::DispatchToAccessor;
|
|
return AccessStrategy::DirectToAccessor;
|
|
}
|
|
llvm_unreachable("bad storage kind");
|
|
}
|
|
llvm_unreachable("bad access semantics");
|
|
}
|
|
|
|
bool ValueDecl::isDefinition() const {
|
|
switch (getKind()) {
|
|
case DeclKind::Import:
|
|
case DeclKind::Extension:
|
|
case DeclKind::PatternBinding:
|
|
case DeclKind::EnumCase:
|
|
case DeclKind::Subscript:
|
|
case DeclKind::TopLevelCode:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
case DeclKind::IfConfig:
|
|
llvm_unreachable("non-value decls shouldn't get here");
|
|
|
|
case DeclKind::Func:
|
|
case DeclKind::Constructor:
|
|
case DeclKind::Destructor:
|
|
return cast<AbstractFunctionDecl>(this)->hasBody();
|
|
|
|
case DeclKind::Var:
|
|
case DeclKind::Param:
|
|
case DeclKind::Enum:
|
|
case DeclKind::EnumElement:
|
|
case DeclKind::Struct:
|
|
case DeclKind::Class:
|
|
case DeclKind::TypeAlias:
|
|
case DeclKind::GenericTypeParam:
|
|
case DeclKind::AssociatedType:
|
|
case DeclKind::Protocol:
|
|
case DeclKind::Module:
|
|
return true;
|
|
}
|
|
llvm_unreachable("bad DeclKind");
|
|
}
|
|
|
|
bool ValueDecl::isInstanceMember() const {
|
|
DeclContext *DC = getDeclContext();
|
|
if (!DC->isTypeContext())
|
|
return false;
|
|
|
|
switch (getKind()) {
|
|
case DeclKind::Import:
|
|
case DeclKind::Extension:
|
|
case DeclKind::PatternBinding:
|
|
case DeclKind::EnumCase:
|
|
case DeclKind::TopLevelCode:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
case DeclKind::IfConfig:
|
|
llvm_unreachable("Not a ValueDecl");
|
|
|
|
case DeclKind::Class:
|
|
case DeclKind::Enum:
|
|
case DeclKind::Protocol:
|
|
case DeclKind::Struct:
|
|
case DeclKind::TypeAlias:
|
|
case DeclKind::GenericTypeParam:
|
|
case DeclKind::AssociatedType:
|
|
// Types are not instance members.
|
|
return false;
|
|
|
|
case DeclKind::Constructor:
|
|
// Constructors are not instance members.
|
|
return false;
|
|
|
|
case DeclKind::Destructor:
|
|
// Destructors are technically instance members, although they
|
|
// can't actually be referenced as such.
|
|
return true;
|
|
|
|
case DeclKind::Func:
|
|
// Non-static methods are instance members.
|
|
return !cast<FuncDecl>(this)->isStatic();
|
|
|
|
case DeclKind::EnumElement:
|
|
case DeclKind::Param:
|
|
// enum elements and function parameters are not instance members.
|
|
return false;
|
|
|
|
case DeclKind::Subscript:
|
|
// Subscripts are always instance members.
|
|
return true;
|
|
|
|
case DeclKind::Var:
|
|
// Non-static variables are instance members.
|
|
return !cast<VarDecl>(this)->isStatic();
|
|
|
|
case DeclKind::Module:
|
|
// Modules are never instance members.
|
|
return false;
|
|
}
|
|
llvm_unreachable("bad DeclKind");
|
|
}
|
|
|
|
bool ValueDecl::needsCapture() const {
|
|
// We don't need to capture anything from non-local contexts.
|
|
if (!getDeclContext()->isLocalContext())
|
|
return false;
|
|
// We don't need to capture types.
|
|
if (isa<TypeDecl>(this))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
ValueDecl *ValueDecl::getOverriddenDecl() const {
|
|
if (auto fd = dyn_cast<FuncDecl>(this))
|
|
return fd->getOverriddenDecl();
|
|
if (auto sdd = dyn_cast<AbstractStorageDecl>(this))
|
|
return sdd->getOverriddenDecl();
|
|
if (auto cd = dyn_cast<ConstructorDecl>(this))
|
|
return cd->getOverriddenDecl();
|
|
return nullptr;
|
|
}
|
|
|
|
bool swift::conflicting(const OverloadSignature& sig1,
|
|
const OverloadSignature& sig2) {
|
|
// A member of a protocol extension never conflicts with a member of a
|
|
// protocol.
|
|
if (sig1.InProtocolExtension != sig2.InProtocolExtension)
|
|
return false;
|
|
|
|
// If the base names are different, they can't conflict.
|
|
if (sig1.Name.getBaseName() != sig2.Name.getBaseName())
|
|
return false;
|
|
|
|
// If one is a compound name and the other is not, they do not conflict
|
|
// if one is a property and the other is a non-nullary function.
|
|
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
|
|
return !((sig1.IsProperty && sig2.Name.getArgumentNames().size() > 0) ||
|
|
(sig2.IsProperty && sig1.Name.getArgumentNames().size() > 0));
|
|
}
|
|
|
|
return sig1.Name == sig2.Name &&
|
|
sig1.InterfaceType == sig2.InterfaceType &&
|
|
sig1.UnaryOperator == sig2.UnaryOperator &&
|
|
sig1.IsInstanceMember == sig2.IsInstanceMember;
|
|
}
|
|
|
|
static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
|
|
bool topLevelFunction,
|
|
bool isMethod,
|
|
bool isInitializer,
|
|
unsigned curryLevels);
|
|
|
|
/// Map a type within the signature of a declaration.
|
|
static Type mapSignatureType(ASTContext &ctx, Type type) {
|
|
return type.transform([&](Type type) -> Type {
|
|
if (type->is<FunctionType>()) {
|
|
return mapSignatureFunctionType(ctx, type, false, false, false, 1);
|
|
}
|
|
|
|
return type;
|
|
});
|
|
}
|
|
|
|
/// Map a signature type for a parameter.
|
|
static Type mapSignatureParamType(ASTContext &ctx, Type type) {
|
|
/// Translate implicitly unwrapped optionals into strict optionals.
|
|
if (auto uncheckedOptOf = type->getImplicitlyUnwrappedOptionalObjectType()) {
|
|
type = OptionalType::get(uncheckedOptOf);
|
|
}
|
|
|
|
return mapSignatureType(ctx, type);
|
|
}
|
|
|
|
/// Map an ExtInfo for a function type.
|
|
///
|
|
/// When checking if two signatures should be equivalent for overloading,
|
|
/// we may need to compare the extended information.
|
|
///
|
|
/// In the type of the function declaration, none of the extended information
|
|
/// is relevant. We cannot overload purely on @noreturn, 'throws', or the
|
|
/// calling convention of the declaration itself.
|
|
///
|
|
/// For function parameter types, we do want to be able to overload on
|
|
/// 'throws', since that is part of the mangled symbol name, but not
|
|
/// @noreturn or @noescape.
|
|
static AnyFunctionType::ExtInfo
|
|
mapSignatureExtInfo(AnyFunctionType::ExtInfo info,
|
|
bool topLevelFunction) {
|
|
if (topLevelFunction)
|
|
return AnyFunctionType::ExtInfo();
|
|
return AnyFunctionType::ExtInfo()
|
|
.withRepresentation(info.getRepresentation())
|
|
.withIsAutoClosure(info.isAutoClosure())
|
|
.withThrows(info.throws());
|
|
}
|
|
|
|
/// Map a function's type to the type used for computing signatures,
|
|
/// which involves stripping some attributes, stripping default arguments,
|
|
/// transforming implicitly unwrapped optionals into strict optionals,
|
|
/// stripping 'inout' on the 'self' parameter etc.
|
|
static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
|
|
bool topLevelFunction,
|
|
bool isMethod,
|
|
bool isInitializer,
|
|
unsigned curryLevels) {
|
|
if (curryLevels == 0) {
|
|
// In an initializer, ignore optionality.
|
|
if (isInitializer) {
|
|
if (auto objectType = type->getAnyOptionalObjectType())
|
|
type = objectType;
|
|
}
|
|
|
|
// Translate implicitly unwrapped optionals into strict optionals.
|
|
if (auto uncheckedOptOf = type->getImplicitlyUnwrappedOptionalObjectType()) {
|
|
type = OptionalType::get(uncheckedOptOf);
|
|
}
|
|
|
|
return mapSignatureType(ctx, type);
|
|
}
|
|
|
|
auto funcTy = type->castTo<AnyFunctionType>();
|
|
auto argTy = funcTy->getInput();
|
|
|
|
if (auto tupleTy = argTy->getAs<TupleType>()) {
|
|
SmallVector<TupleTypeElt, 4> elements;
|
|
bool anyChanged = false;
|
|
unsigned idx = 0;
|
|
for (const auto &elt : tupleTy->getElements()) {
|
|
Type eltTy = mapSignatureParamType(ctx, elt.getType());
|
|
if (anyChanged || eltTy.getPointer() != elt.getType().getPointer() ||
|
|
elt.getDefaultArgKind() != DefaultArgumentKind::None) {
|
|
if (!anyChanged) {
|
|
elements.reserve(tupleTy->getNumElements());
|
|
for (unsigned i = 0; i != idx; ++i) {
|
|
const TupleTypeElt &elt = tupleTy->getElement(i);
|
|
elements.push_back(TupleTypeElt(elt.getType(), elt.getName(),
|
|
DefaultArgumentKind::None,
|
|
elt.isVararg()));
|
|
}
|
|
anyChanged = true;
|
|
}
|
|
|
|
elements.push_back(TupleTypeElt(eltTy, elt.getName(),
|
|
DefaultArgumentKind::None,
|
|
elt.isVararg()));
|
|
}
|
|
++idx;
|
|
}
|
|
|
|
if (anyChanged) {
|
|
argTy = TupleType::get(elements, ctx);
|
|
}
|
|
} else {
|
|
argTy = mapSignatureParamType(ctx, argTy);
|
|
|
|
if (isMethod) {
|
|
// In methods, strip the 'inout' off of 'self' so that mutating and
|
|
// non-mutating methods have the same self parameter type.
|
|
if (auto inoutTy = argTy->getAs<InOutType>()) {
|
|
argTy = inoutTy->getObjectType();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Map the result type.
|
|
auto resultTy = mapSignatureFunctionType(
|
|
ctx, funcTy->getResult(), topLevelFunction, false, isInitializer,
|
|
curryLevels - 1);
|
|
|
|
// Map various attributes differently depending on if we're looking at
|
|
// the declaration, or a function parameter type.
|
|
AnyFunctionType::ExtInfo info = mapSignatureExtInfo(
|
|
funcTy->getExtInfo(), topLevelFunction);
|
|
|
|
// Rebuild the resulting function type.
|
|
if (auto genericFuncTy = dyn_cast<GenericFunctionType>(funcTy))
|
|
return GenericFunctionType::get(genericFuncTy->getGenericSignature(),
|
|
argTy, resultTy, info);
|
|
|
|
return FunctionType::get(argTy, resultTy, info);
|
|
}
|
|
|
|
OverloadSignature ValueDecl::getOverloadSignature() const {
|
|
OverloadSignature signature;
|
|
|
|
signature.Name = getFullName();
|
|
signature.InProtocolExtension
|
|
= getDeclContext()->isProtocolExtensionContext();
|
|
|
|
// Functions, initializers, and de-initializers include their
|
|
// interface types in their signatures as well as whether they are
|
|
// instance members.
|
|
if (auto afd = dyn_cast<AbstractFunctionDecl>(this)) {
|
|
signature.InterfaceType =
|
|
mapSignatureFunctionType(
|
|
getASTContext(), getInterfaceType(),
|
|
/*topLevelFunction=*/true,
|
|
/*isMethod=*/afd->getImplicitSelfDecl() != nullptr,
|
|
/*isInitializer=*/isa<ConstructorDecl>(afd),
|
|
afd->getNumParameterLists())->getCanonicalType();
|
|
|
|
signature.IsInstanceMember = isInstanceMember();
|
|
// Unary operators also include prefix/postfix.
|
|
if (auto func = dyn_cast<FuncDecl>(this)) {
|
|
if (func->isUnaryOperator()) {
|
|
signature.UnaryOperator = func->getAttrs().getUnaryOperatorKind();
|
|
}
|
|
}
|
|
} else if (isa<SubscriptDecl>(this)) {
|
|
signature.InterfaceType
|
|
= getInterfaceType()->getWithoutDefaultArgs(getASTContext())
|
|
->getCanonicalType();
|
|
|
|
// If the subscript occurs within a generic extension context,
|
|
// consider the generic signature of the extension.
|
|
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext())) {
|
|
if (auto genericSig = ext->getGenericSignature()) {
|
|
auto funcTy = signature.InterfaceType->castTo<AnyFunctionType>();
|
|
signature.InterfaceType
|
|
= GenericFunctionType::get(genericSig,
|
|
funcTy->getInput(),
|
|
funcTy->getResult(),
|
|
funcTy->getExtInfo())
|
|
->getCanonicalType();
|
|
}
|
|
}
|
|
} else if (isa<VarDecl>(this)) {
|
|
signature.IsProperty = true;
|
|
signature.IsInstanceMember = isInstanceMember();
|
|
|
|
// If the property occurs within a generic extension context,
|
|
// consider the generic signature of the extension.
|
|
if (auto ext = dyn_cast<ExtensionDecl>(getDeclContext())) {
|
|
if (auto genericSig = ext->getGenericSignature()) {
|
|
ASTContext &ctx = getASTContext();
|
|
signature.InterfaceType
|
|
= GenericFunctionType::get(genericSig,
|
|
TupleType::getEmpty(ctx),
|
|
TupleType::getEmpty(ctx),
|
|
AnyFunctionType::ExtInfo())
|
|
->getCanonicalType();
|
|
}
|
|
}
|
|
}
|
|
|
|
return signature;
|
|
}
|
|
|
|
void ValueDecl::setIsObjC(bool Value) {
|
|
bool CurrentValue = isObjC();
|
|
if (CurrentValue == Value)
|
|
return;
|
|
|
|
if (!Value) {
|
|
for (auto *Attr : getAttrs()) {
|
|
if (auto *OA = dyn_cast<ObjCAttr>(Attr))
|
|
OA->setInvalid();
|
|
}
|
|
} else {
|
|
getAttrs().add(ObjCAttr::createUnnamedImplicit(getASTContext()));
|
|
}
|
|
}
|
|
|
|
bool ValueDecl::canBeAccessedByDynamicLookup() const {
|
|
if (!hasName())
|
|
return false;
|
|
|
|
// Dynamic lookup can only find [objc] members.
|
|
if (!isObjC())
|
|
return false;
|
|
|
|
// Dynamic lookup can only find class and protocol members, or extensions of
|
|
// classes.
|
|
auto declaredType = getDeclContext()->getDeclaredTypeOfContext();
|
|
|
|
if (!declaredType)
|
|
return false;
|
|
|
|
auto nominalDC = declaredType->getAnyNominal();
|
|
if (!nominalDC ||
|
|
(!isa<ClassDecl>(nominalDC) && !isa<ProtocolDecl>(nominalDC)))
|
|
return false;
|
|
|
|
// Dynamic lookup cannot find results within a non-protocol generic context,
|
|
// because there is no sensible way to infer the generic arguments.
|
|
if (getDeclContext()->isGenericContext() && !isa<ProtocolDecl>(nominalDC))
|
|
return false;
|
|
|
|
// Dynamic lookup can find functions, variables, and subscripts.
|
|
if (isa<FuncDecl>(this) || isa<VarDecl>(this) || isa<SubscriptDecl>(this))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
ArrayRef<ValueDecl *>
|
|
ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const {
|
|
// Dig out the nominal type.
|
|
NominalTypeDecl *NTD =
|
|
getDeclContext()->isNominalTypeOrNominalTypeExtensionContext();
|
|
if (!NTD || isa<ProtocolDecl>(NTD))
|
|
return {};
|
|
|
|
return NTD->getSatisfiedProtocolRequirementsForMember(this, Sorted);
|
|
}
|
|
|
|
void ValueDecl::setType(Type T) {
|
|
assert(!hasType() && "changing type of declaration");
|
|
overwriteType(T);
|
|
}
|
|
|
|
void ValueDecl::overwriteType(Type T) {
|
|
TypeAndAccess.setPointer(T);
|
|
if (!T.isNull() && T->is<ErrorType>())
|
|
setInvalid();
|
|
}
|
|
|
|
Type ValueDecl::getInterfaceType() const {
|
|
if (InterfaceTy)
|
|
return InterfaceTy;
|
|
|
|
if (auto nominal = dyn_cast<NominalTypeDecl>(this))
|
|
return nominal->computeInterfaceType();
|
|
|
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(this)) {
|
|
auto proto = cast<ProtocolDecl>(getDeclContext());
|
|
(void)proto->getType(); // make sure we've computed the type.
|
|
// FIXME: the generic parameter types list should never be empty.
|
|
auto selfTy = proto->getGenericParamTypes().empty()
|
|
? proto->getProtocolSelf()->getType()
|
|
: proto->getGenericParamTypes().back();
|
|
auto &ctx = getASTContext();
|
|
InterfaceTy = DependentMemberType::get(
|
|
selfTy,
|
|
const_cast<AssociatedTypeDecl *>(assocType),
|
|
ctx);
|
|
InterfaceTy = MetatypeType::get(InterfaceTy, ctx);
|
|
return InterfaceTy;
|
|
}
|
|
|
|
if (!hasType())
|
|
return Type();
|
|
|
|
// If the type involves a type variable, don't cache it.
|
|
auto type = getType();
|
|
assert((type.isNull() || !type->is<PolymorphicFunctionType>())
|
|
&& "decl has polymorphic function type but no interface type");
|
|
|
|
if (type->hasTypeVariable())
|
|
return type;
|
|
|
|
InterfaceTy = type;
|
|
return InterfaceTy;
|
|
}
|
|
|
|
void ValueDecl::setInterfaceType(Type type) {
|
|
assert((type.isNull() || !type->hasTypeVariable()) &&
|
|
"Type variable in interface type");
|
|
assert((type.isNull() || !type->is<PolymorphicFunctionType>()) &&
|
|
"setting polymorphic function type as interface type");
|
|
|
|
InterfaceTy = type;
|
|
}
|
|
|
|
SourceLoc ValueDecl::getAttributeInsertionLoc(bool forModifier) const {
|
|
if (auto var = dyn_cast<VarDecl>(this)) {
|
|
if (auto pbd = var->getParentPatternBinding()) {
|
|
SourceLoc resultLoc = pbd->getAttrs().getStartLoc(forModifier);
|
|
return resultLoc.isValid() ? resultLoc : pbd->getStartLoc();
|
|
}
|
|
}
|
|
|
|
SourceLoc resultLoc = getAttrs().getStartLoc(forModifier);
|
|
return resultLoc.isValid() ? resultLoc : getStartLoc();
|
|
}
|
|
|
|
|
|
Type TypeDecl::getDeclaredType() const {
|
|
if (auto TAD = dyn_cast<TypeAliasDecl>(this)) {
|
|
if (TAD->hasType() && TAD->getType()->is<ErrorType>())
|
|
return TAD->getType();
|
|
|
|
return TAD->getAliasType();
|
|
}
|
|
if (auto typeParam = dyn_cast<AbstractTypeParamDecl>(this)) {
|
|
auto type = typeParam->getType();
|
|
if (type->is<ErrorType>())
|
|
return type;
|
|
|
|
return type->castTo<MetatypeType>()->getInstanceType();
|
|
}
|
|
if (auto module = dyn_cast<ModuleDecl>(this)) {
|
|
return ModuleType::get(const_cast<ModuleDecl *>(module));
|
|
}
|
|
return cast<NominalTypeDecl>(this)->getDeclaredType();
|
|
}
|
|
|
|
Type TypeDecl::getDeclaredInterfaceType() const {
|
|
Type interfaceType = getInterfaceType();
|
|
if (interfaceType->is<ErrorType>())
|
|
return interfaceType;
|
|
|
|
return interfaceType->castTo<MetatypeType>()->getInstanceType();
|
|
}
|
|
|
|
|
|
bool NominalTypeDecl::hasFixedLayout() const {
|
|
// Private and internal types always have a fixed layout.
|
|
// TODO: internal types with availability information need to be
|
|
// resilient, since they can be used from @_transparent functions.
|
|
if (getFormalAccess() != Accessibility::Public)
|
|
return true;
|
|
|
|
// Check for an explicit @_fixed_layout attribute.
|
|
if (getAttrs().hasAttribute<FixedLayoutAttr>())
|
|
return true;
|
|
|
|
if (hasClangNode()) {
|
|
// Classes imported from Objective-C *never* have a fixed layout.
|
|
// IRGen needs to use dynamic ivar layout to ensure that subclasses
|
|
// of Objective-C classes are resilient against base class size
|
|
// changes.
|
|
if (isa<ClassDecl>(this))
|
|
return false;
|
|
|
|
// Structs and enums imported from C *always* have a fixed layout.
|
|
// We know their size, and pass them as values in SIL and IRGen.
|
|
return true;
|
|
}
|
|
|
|
// Objective-C enums always have a fixed layout.
|
|
if (isa<EnumDecl>(this) && isObjC())
|
|
return true;
|
|
|
|
// Otherwise, access via indirect "resilient" interfaces.
|
|
return false;
|
|
}
|
|
|
|
/// Provide the set of parameters to a generic type, or null if
|
|
/// this function is not generic.
|
|
void NominalTypeDecl::setGenericParams(GenericParamList *params) {
|
|
assert(!GenericParams && "Already has generic parameters");
|
|
GenericParams = params;
|
|
|
|
if (params)
|
|
for (auto Param : *params)
|
|
Param->setDeclContext(this);
|
|
}
|
|
|
|
|
|
bool NominalTypeDecl::derivesProtocolConformance(ProtocolDecl *protocol) const {
|
|
// Only known protocols can be derived.
|
|
auto knownProtocol = protocol->getKnownProtocolKind();
|
|
if (!knownProtocol)
|
|
return false;
|
|
|
|
// All nominal types can derive their ErrorType conformance.
|
|
if (*knownProtocol == KnownProtocolKind::ErrorType)
|
|
return true;
|
|
|
|
if (auto *enumDecl = dyn_cast<EnumDecl>(this)) {
|
|
switch (*knownProtocol) {
|
|
// Enums with raw types can implicitly derive their RawRepresentable
|
|
// conformance.
|
|
case KnownProtocolKind::RawRepresentable:
|
|
return enumDecl->hasRawType();
|
|
|
|
// Enums without associated values can implicitly derive Equatable and
|
|
// Hashable conformance.
|
|
case KnownProtocolKind::Equatable:
|
|
case KnownProtocolKind::Hashable:
|
|
return enumDecl->hasOnlyCasesWithoutAssociatedValues();
|
|
|
|
// @objc enums can explicitly derive their _BridgedNSError conformance.
|
|
case KnownProtocolKind::BridgedNSError:
|
|
return isObjC() && enumDecl->hasOnlyCasesWithoutAssociatedValues();
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void NominalTypeDecl::setGenericSignature(GenericSignature *sig) {
|
|
assert(!GenericSig && "Already have generic signature");
|
|
GenericSig = sig;
|
|
}
|
|
|
|
void NominalTypeDecl::computeType() {
|
|
assert(!hasType() && "Nominal type declaration already has a type");
|
|
|
|
// Compute the declared type.
|
|
Type parentTy = getDeclContext()->getDeclaredTypeInContext();
|
|
ASTContext &ctx = getASTContext();
|
|
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
|
|
if (!getDeclaredType()) {
|
|
ProtocolType::get(proto, ctx);
|
|
assert(getDeclaredType());
|
|
}
|
|
} else if (getGenericParams()) {
|
|
setDeclaredType(UnboundGenericType::get(this, parentTy, ctx));
|
|
} else {
|
|
setDeclaredType(NominalType::get(this, parentTy, ctx));
|
|
}
|
|
|
|
// Set the type.
|
|
setType(MetatypeType::get(DeclaredTy, ctx));
|
|
|
|
// A protocol has an implicit generic parameter list consisting of a single
|
|
// generic parameter, Self, that conforms to the protocol itself. This
|
|
// parameter is always implicitly bound.
|
|
//
|
|
// If this protocol has been deserialized, it already has generic parameters.
|
|
// Don't add them again.
|
|
if (!getGenericParams()) {
|
|
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
|
|
GenericParams = proto->createGenericParams(proto);
|
|
}
|
|
}
|
|
}
|
|
|
|
Type NominalTypeDecl::getDeclaredTypeInContext() const {
|
|
if (DeclaredTyInContext)
|
|
return DeclaredTyInContext;
|
|
|
|
Type Ty = getDeclaredType();
|
|
if (!Ty)
|
|
return Ty;
|
|
|
|
if (UnboundGenericType *UGT = Ty->getAs<UnboundGenericType>()) {
|
|
// If we have an unbound generic type, bind the type to the archetypes
|
|
// in the type's definition.
|
|
NominalTypeDecl *D = UGT->getDecl();
|
|
SmallVector<Type, 4> GenericArgs;
|
|
for (auto Param : *D->getGenericParams()) {
|
|
auto Archetype = Param->getArchetype();
|
|
if (!Archetype)
|
|
return ErrorType::get(getASTContext());
|
|
|
|
GenericArgs.push_back(Archetype);
|
|
}
|
|
Ty = BoundGenericType::get(D, getDeclContext()->getDeclaredTypeInContext(),
|
|
GenericArgs);
|
|
}
|
|
const_cast<NominalTypeDecl *>(this)->DeclaredTyInContext = Ty;
|
|
return DeclaredTyInContext;
|
|
}
|
|
|
|
Type NominalTypeDecl::computeInterfaceType() const {
|
|
if (InterfaceTy)
|
|
return InterfaceTy;
|
|
|
|
// Figure out the interface type of the parent.
|
|
Type parentType;
|
|
if (auto parent = getDeclContext()->isNominalTypeOrNominalTypeExtensionContext())
|
|
parentType = parent->getDeclaredInterfaceType();
|
|
|
|
Type type;
|
|
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
|
|
type = ProtocolType::get(const_cast<ProtocolDecl *>(proto),getASTContext());
|
|
} else if (auto params = getGenericParams()) {
|
|
// If we have a generic type, bind the type to the archetypes
|
|
// in the type's definition.
|
|
SmallVector<Type, 4> genericArgs;
|
|
for (auto param : *params)
|
|
genericArgs.push_back(param->getDeclaredType());
|
|
|
|
type = BoundGenericType::get(const_cast<NominalTypeDecl *>(this),
|
|
parentType, genericArgs);
|
|
} else {
|
|
type = NominalType::get(const_cast<NominalTypeDecl *>(this), parentType,
|
|
getASTContext());
|
|
}
|
|
|
|
InterfaceTy = MetatypeType::get(type, getASTContext());
|
|
return InterfaceTy;
|
|
|
|
}
|
|
|
|
void NominalTypeDecl::prepareExtensions() {
|
|
auto &context = Decl::getASTContext();
|
|
|
|
// If our list of extensions is out of date, update it now.
|
|
if (context.getCurrentGeneration() > ExtensionGeneration) {
|
|
unsigned previousGeneration = ExtensionGeneration;
|
|
ExtensionGeneration = context.getCurrentGeneration();
|
|
context.loadExtensions(this, previousGeneration);
|
|
}
|
|
}
|
|
|
|
ExtensionRange NominalTypeDecl::getExtensions() {
|
|
prepareExtensions();
|
|
return ExtensionRange(ExtensionIterator(FirstExtension), ExtensionIterator());
|
|
}
|
|
|
|
void NominalTypeDecl::addExtension(ExtensionDecl *extension) {
|
|
assert(!extension->NextExtension.getInt() && "Already added extension");
|
|
extension->NextExtension.setInt(true);
|
|
|
|
// First extension; set both first and last.
|
|
if (!FirstExtension) {
|
|
FirstExtension = extension;
|
|
LastExtension = extension;
|
|
return;
|
|
}
|
|
|
|
// Add to the end of the list.
|
|
LastExtension->NextExtension.setPointer(extension);
|
|
LastExtension = extension;
|
|
}
|
|
|
|
OptionalTypeKind NominalTypeDecl::classifyAsOptionalType() const {
|
|
const ASTContext &ctx = getASTContext();
|
|
if (this == ctx.getOptionalDecl()) {
|
|
return OTK_Optional;
|
|
} else if (this == ctx.getImplicitlyUnwrappedOptionalDecl()) {
|
|
return OTK_ImplicitlyUnwrappedOptional;
|
|
} else {
|
|
return OTK_None;
|
|
}
|
|
}
|
|
|
|
TypeAliasDecl::TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
|
|
SourceLoc NameLoc, TypeLoc UnderlyingTy,
|
|
DeclContext *DC)
|
|
: TypeDecl(DeclKind::TypeAlias, DC, Name, NameLoc, {}),
|
|
TypeAliasLoc(TypeAliasLoc),
|
|
UnderlyingTy(UnderlyingTy)
|
|
{
|
|
// Set the type of the TypeAlias to the right MetatypeType.
|
|
ASTContext &Ctx = getASTContext();
|
|
AliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
|
|
}
|
|
|
|
void TypeAliasDecl::computeType() {
|
|
ASTContext &ctx = getASTContext();
|
|
setType(MetatypeType::get(AliasTy, ctx));
|
|
}
|
|
|
|
SourceRange TypeAliasDecl::getSourceRange() const {
|
|
if (UnderlyingTy.hasLocation())
|
|
return { TypeAliasLoc, UnderlyingTy.getSourceRange().End };
|
|
return { TypeAliasLoc, getNameLoc() };
|
|
}
|
|
|
|
Type AbstractTypeParamDecl::getSuperclass() const {
|
|
if (Archetype)
|
|
return Archetype->getSuperclass();
|
|
|
|
// FIXME: Assert that this is never queried.
|
|
return nullptr;
|
|
}
|
|
|
|
ArrayRef<ProtocolDecl *> AbstractTypeParamDecl::getConformingProtocols(
|
|
LazyResolver *resolver) const {
|
|
if (Archetype)
|
|
return Archetype->getConformsTo();
|
|
|
|
// FIXME: Assert that this is never queried.
|
|
return { };
|
|
}
|
|
|
|
GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
|
|
SourceLoc nameLoc,
|
|
unsigned depth, unsigned index)
|
|
: AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name, nameLoc),
|
|
Depth(depth), Index(index)
|
|
{
|
|
auto &ctx = dc->getASTContext();
|
|
auto type = new (ctx, AllocationArena::Permanent) GenericTypeParamType(this);
|
|
setType(MetatypeType::get(type, ctx));
|
|
}
|
|
|
|
SourceRange GenericTypeParamDecl::getSourceRange() const {
|
|
SourceLoc endLoc = getNameLoc();
|
|
|
|
if (!getInherited().empty()) {
|
|
endLoc = getInherited().back().getSourceRange().End;
|
|
}
|
|
return SourceRange(getNameLoc(), endLoc);
|
|
}
|
|
|
|
bool GenericTypeParamDecl::isProtocolSelf() const {
|
|
if (!isImplicit()) return false;
|
|
auto dc = getDeclContext();
|
|
if (!dc->isProtocolOrProtocolExtensionContext()) return false;
|
|
return dc->getProtocolSelf() == this;
|
|
}
|
|
|
|
|
|
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
|
|
Identifier name, SourceLoc nameLoc,
|
|
TypeLoc defaultDefinition)
|
|
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
|
|
KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition)
|
|
{
|
|
AssociatedTypeDeclBits.Recursive = 0;
|
|
}
|
|
|
|
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
|
|
Identifier name, SourceLoc nameLoc,
|
|
LazyMemberLoader *definitionResolver,
|
|
uint64_t resolverData)
|
|
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name, nameLoc),
|
|
KeywordLoc(keywordLoc), Resolver(definitionResolver),
|
|
ResolverContextData(resolverData)
|
|
{
|
|
assert(Resolver && "missing resolver");
|
|
AssociatedTypeDeclBits.Recursive = 0;
|
|
}
|
|
|
|
void AssociatedTypeDecl::computeType() {
|
|
auto &ctx = getASTContext();
|
|
auto type = new (ctx, AllocationArena::Permanent) AssociatedTypeType(this);
|
|
setType(MetatypeType::get(type, ctx));
|
|
}
|
|
|
|
TypeLoc &AssociatedTypeDecl::getDefaultDefinitionLoc() {
|
|
if (Resolver) {
|
|
DefaultDefinition =
|
|
Resolver->loadAssociatedTypeDefault(this, ResolverContextData);
|
|
Resolver = nullptr;
|
|
}
|
|
return DefaultDefinition;
|
|
}
|
|
|
|
SourceRange AssociatedTypeDecl::getSourceRange() const {
|
|
SourceLoc endLoc = getNameLoc();
|
|
|
|
if (!getInherited().empty()) {
|
|
endLoc = getInherited().back().getSourceRange().End;
|
|
}
|
|
return SourceRange(KeywordLoc, endLoc);
|
|
}
|
|
|
|
EnumDecl::EnumDecl(SourceLoc EnumLoc,
|
|
Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Enum, Parent, Name, NameLoc, Inherited,
|
|
GenericParams),
|
|
EnumLoc(EnumLoc)
|
|
{
|
|
EnumDeclBits.Circularity
|
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
|
}
|
|
|
|
StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Struct, Parent, Name, NameLoc, Inherited,
|
|
GenericParams),
|
|
StructLoc(StructLoc)
|
|
{
|
|
StructDeclBits.HasUnreferenceableStorage = false;
|
|
}
|
|
|
|
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Class, Parent, Name, NameLoc, Inherited,
|
|
GenericParams),
|
|
ClassLoc(ClassLoc) {
|
|
ClassDeclBits.Circularity
|
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
|
ClassDeclBits.RequiresStoredPropertyInits = 0;
|
|
ClassDeclBits.InheritsSuperclassInits
|
|
= static_cast<unsigned>(StoredInheritsSuperclassInits::Unchecked);
|
|
ClassDeclBits.Foreign = false;
|
|
ClassDeclBits.HasDestructorDecl = 0;
|
|
}
|
|
|
|
DestructorDecl *ClassDecl::getDestructor() {
|
|
auto name = getASTContext().Id_deinit;
|
|
auto results = lookupDirect(name);
|
|
assert(!results.empty() && "Class without destructor?");
|
|
assert(results.size() == 1 && "More than one destructor?");
|
|
return cast<DestructorDecl>(results.front());
|
|
}
|
|
|
|
bool ClassDecl::inheritsSuperclassInitializers(LazyResolver *resolver) {
|
|
// Check whether we already have a cached answer.
|
|
switch (static_cast<StoredInheritsSuperclassInits>(
|
|
ClassDeclBits.InheritsSuperclassInits)) {
|
|
case StoredInheritsSuperclassInits::Unchecked:
|
|
// Compute below.
|
|
break;
|
|
|
|
case StoredInheritsSuperclassInits::Inherited:
|
|
return true;
|
|
|
|
case StoredInheritsSuperclassInits::NotInherited:
|
|
return false;
|
|
}
|
|
|
|
// If there's no superclass, there's nothing to inherit.
|
|
ClassDecl *superclassDecl;
|
|
if (!getSuperclass() ||
|
|
!(superclassDecl = getSuperclass()->getClassOrBoundGenericClass())) {
|
|
ClassDeclBits.InheritsSuperclassInits
|
|
= static_cast<unsigned>(StoredInheritsSuperclassInits::NotInherited);
|
|
return false;
|
|
}
|
|
|
|
// Look at all of the initializers of the subclass to gather the initializers
|
|
// they override from the superclass.
|
|
auto &ctx = getASTContext();
|
|
llvm::SmallPtrSet<ConstructorDecl *, 4> overriddenInits;
|
|
if (resolver)
|
|
resolver->resolveImplicitConstructors(this);
|
|
for (auto member : lookupDirect(ctx.Id_init)) {
|
|
auto ctor = dyn_cast<ConstructorDecl>(member);
|
|
if (!ctor)
|
|
continue;
|
|
|
|
// Resolve this initializer, if needed.
|
|
if (!ctor->hasType())
|
|
resolver->resolveDeclSignature(ctor);
|
|
|
|
// Ignore any stub implementations.
|
|
if (ctor->hasStubImplementation())
|
|
continue;
|
|
|
|
if (auto overridden = ctor->getOverriddenDecl()) {
|
|
if (overridden->isDesignatedInit())
|
|
overriddenInits.insert(overridden);
|
|
}
|
|
}
|
|
|
|
// Check all of the designated initializers in the direct superclass.
|
|
// Note: This should be treated as a lookup for intra-module dependency
|
|
// purposes, but a subclass already depends on its superclasses and any
|
|
// extensions for many other reasons.
|
|
for (auto member : superclassDecl->lookupDirect(ctx.Id_init)) {
|
|
if (AvailableAttr::isUnavailable(member))
|
|
continue;
|
|
|
|
// We only care about designated initializers.
|
|
auto ctor = dyn_cast<ConstructorDecl>(member);
|
|
if (!ctor || !ctor->isDesignatedInit() || ctor->hasStubImplementation())
|
|
continue;
|
|
|
|
// If this designated initializer wasn't overridden, we can't inherit.
|
|
if (overriddenInits.count(ctor) == 0) {
|
|
ClassDeclBits.InheritsSuperclassInits
|
|
= static_cast<unsigned>(StoredInheritsSuperclassInits::NotInherited);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// All of the direct superclass's designated initializers have been overridden
|
|
// by the subclass. Initializers can be inherited.
|
|
ClassDeclBits.InheritsSuperclassInits
|
|
= static_cast<unsigned>(StoredInheritsSuperclassInits::Inherited);
|
|
return true;
|
|
}
|
|
|
|
ObjCClassKind ClassDecl::checkObjCAncestry() const {
|
|
llvm::SmallPtrSet<const ClassDecl *, 8> visited;
|
|
bool genericAncestry = false, isObjC = false;
|
|
const ClassDecl *CD = this;
|
|
|
|
for (;;) {
|
|
// If we hit circularity, we will diagnose at some point in typeCheckDecl().
|
|
// However we have to explicitly guard against that here because we get
|
|
// called as part of validateDecl().
|
|
if (!visited.insert(CD).second)
|
|
break;
|
|
|
|
if (CD->isGenericContext())
|
|
genericAncestry = true;
|
|
|
|
if (CD->isObjC())
|
|
isObjC = true;
|
|
|
|
if (!CD->hasSuperclass())
|
|
break;
|
|
CD = CD->getSuperclass()->getClassOrBoundGenericClass();
|
|
}
|
|
|
|
if (!isObjC)
|
|
return ObjCClassKind::NonObjC;
|
|
if (genericAncestry)
|
|
return ObjCClassKind::ObjCMembers;
|
|
if (CD == this || !CD->isObjC())
|
|
return ObjCClassKind::ObjCWithSwiftRoot;
|
|
|
|
return ObjCClassKind::ObjC;
|
|
}
|
|
|
|
/// Mangle the name of a protocol or class for use in the Objective-C
|
|
/// runtime.
|
|
static StringRef mangleObjCRuntimeName(const NominalTypeDecl *nominal,
|
|
llvm::SmallVectorImpl<char> &buffer) {
|
|
{
|
|
// Mangle the type.
|
|
Mangle::Mangler mangler(false/*dwarf*/, false/*punycode*/);
|
|
|
|
// We add the "_Tt" prefix to make this a reserved name that will
|
|
// not conflict with any valid Objective-C class or protocol name.
|
|
mangler.append("_Tt");
|
|
|
|
NominalTypeDecl *NTD = const_cast<NominalTypeDecl*>(nominal);
|
|
if (isa<ClassDecl>(nominal)) {
|
|
mangler.mangleNominalType(NTD, Mangle::Mangler::BindGenerics::None);
|
|
} else {
|
|
mangler.mangleProtocolDecl(cast<ProtocolDecl>(NTD));
|
|
}
|
|
|
|
buffer.clear();
|
|
llvm::raw_svector_ostream os(buffer);
|
|
mangler.finalize(os);
|
|
}
|
|
|
|
assert(buffer.size() && "Invalid buffer size");
|
|
return StringRef(buffer.data(), buffer.size());
|
|
}
|
|
|
|
StringRef ClassDecl::getObjCRuntimeName(
|
|
llvm::SmallVectorImpl<char> &buffer) const {
|
|
// If there is an 'objc' attribute with a name, use that name.
|
|
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
|
|
if (auto name = objc->getName())
|
|
return name->getString(buffer);
|
|
}
|
|
|
|
// Produce the mangled name for this class.
|
|
return mangleObjCRuntimeName(this, buffer);
|
|
}
|
|
|
|
ArtificialMainKind ClassDecl::getArtificialMainKind() const {
|
|
if (getAttrs().hasAttribute<UIApplicationMainAttr>())
|
|
return ArtificialMainKind::UIApplicationMain;
|
|
if (getAttrs().hasAttribute<NSApplicationMainAttr>())
|
|
return ArtificialMainKind::NSApplicationMain;
|
|
llvm_unreachable("class has no @ApplicationMain attr?!");
|
|
}
|
|
|
|
AbstractFunctionDecl *
|
|
ClassDecl::findOverridingDecl(const AbstractFunctionDecl *Method) const {
|
|
auto Members = getMembers();
|
|
for (auto M : Members) {
|
|
AbstractFunctionDecl *CurMethod = dyn_cast<AbstractFunctionDecl>(M);
|
|
if (!CurMethod)
|
|
continue;
|
|
if (CurMethod->isOverridingDecl(Method)) {
|
|
return CurMethod;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool AbstractFunctionDecl::isOverridingDecl(
|
|
const AbstractFunctionDecl *Method) const {
|
|
const AbstractFunctionDecl *CurMethod = this;
|
|
while (CurMethod) {
|
|
if (CurMethod == Method)
|
|
return true;
|
|
CurMethod = CurMethod->getOverriddenDecl();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AbstractFunctionDecl *
|
|
ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const {
|
|
const ClassDecl *C = this;
|
|
while (C) {
|
|
auto Members = C->getMembers();
|
|
for (auto M : Members) {
|
|
AbstractFunctionDecl *CurMethod = dyn_cast<AbstractFunctionDecl>(M);
|
|
if (!CurMethod)
|
|
continue;
|
|
if (Method == CurMethod)
|
|
return CurMethod;
|
|
if (CurMethod->isOverridingDecl(Method)) {
|
|
// This class implements a method
|
|
return CurMethod;
|
|
}
|
|
}
|
|
// Check the superclass
|
|
if (!C->hasSuperclass())
|
|
break;
|
|
C = C->getSuperclass()->getClassOrBoundGenericClass();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc,
|
|
ArrayRef<EnumElementDecl *> Elements,
|
|
DeclContext *DC) {
|
|
void *buf = DC->getASTContext()
|
|
.Allocate(sizeof(EnumCaseDecl) +
|
|
sizeof(EnumElementDecl*) * Elements.size(),
|
|
alignof(EnumCaseDecl));
|
|
return ::new (buf) EnumCaseDecl(CaseLoc, Elements, DC);
|
|
}
|
|
|
|
EnumElementDecl *EnumDecl::getElement(Identifier Name) const {
|
|
// FIXME: Linear search is not great for large enum decls.
|
|
for (EnumElementDecl *Elt : getAllElements())
|
|
if (Elt->getName() == Name)
|
|
return Elt;
|
|
return nullptr;
|
|
}
|
|
|
|
bool EnumDecl::hasOnlyCasesWithoutAssociatedValues() const {
|
|
// FIXME: Should probably cache this.
|
|
bool hasElements = false;
|
|
for (auto elt : getAllElements()) {
|
|
hasElements = true;
|
|
if (!elt->getArgumentTypeLoc().isNull())
|
|
return false;
|
|
}
|
|
return hasElements;
|
|
}
|
|
|
|
ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
|
|
SourceLoc NameLoc, Identifier Name,
|
|
MutableArrayRef<TypeLoc> Inherited)
|
|
: NominalTypeDecl(DeclKind::Protocol, DC, Name, NameLoc, Inherited,
|
|
nullptr),
|
|
ProtocolLoc(ProtocolLoc)
|
|
{
|
|
ProtocolDeclBits.RequiresClassValid = false;
|
|
ProtocolDeclBits.RequiresClass = false;
|
|
ProtocolDeclBits.ExistentialConformsToSelfValid = false;
|
|
ProtocolDeclBits.ExistentialConformsToSelf = false;
|
|
ProtocolDeclBits.KnownProtocol = 0;
|
|
ProtocolDeclBits.Circularity
|
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
|
HasMissingRequirements = false;
|
|
InheritedProtocolsSet = false;
|
|
}
|
|
|
|
ArrayRef<ProtocolDecl *>
|
|
ProtocolDecl::getInheritedProtocols(LazyResolver *resolver) const {
|
|
return InheritedProtocols;
|
|
}
|
|
|
|
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const {
|
|
if (this == super)
|
|
return false;
|
|
|
|
auto allProtocols = getLocalProtocols();
|
|
return std::find(allProtocols.begin(), allProtocols.end(), super)
|
|
!= allProtocols.end();
|
|
}
|
|
|
|
bool ProtocolDecl::requiresClassSlow() {
|
|
ProtocolDeclBits.RequiresClass = false;
|
|
|
|
// Ensure that the result cannot change in future.
|
|
assert(isInheritedProtocolsValid() || isBeingTypeChecked());
|
|
|
|
if (getAttrs().hasAttribute<ObjCAttr>() || isObjC()) {
|
|
ProtocolDeclBits.RequiresClass = true;
|
|
return true;
|
|
}
|
|
|
|
// Check inherited protocols for class-ness.
|
|
for (auto *proto : getInheritedProtocols(nullptr)) {
|
|
if (proto->requiresClass()) {
|
|
ProtocolDeclBits.RequiresClass = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ProtocolDecl::existentialConformsToSelfSlow() {
|
|
// Assume for now that the existential conforms to itself; this
|
|
// prevents circularity issues.
|
|
ProtocolDeclBits.ExistentialConformsToSelfValid = true;
|
|
ProtocolDeclBits.ExistentialConformsToSelf = true;
|
|
|
|
if (isSpecificProtocol(KnownProtocolKind::AnyObject))
|
|
return true;
|
|
|
|
if (!isObjC()) {
|
|
ProtocolDeclBits.ExistentialConformsToSelf = false;
|
|
return false;
|
|
}
|
|
|
|
// Check whether this protocol conforms to itself.
|
|
for (auto member : getMembers()) {
|
|
if (member->isInvalid())
|
|
continue;
|
|
|
|
if (auto vd = dyn_cast<ValueDecl>(member)) {
|
|
if (!vd->isInstanceMember()) {
|
|
// A protocol cannot conform to itself if it has static members.
|
|
ProtocolDeclBits.ExistentialConformsToSelf = false;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check whether any of the inherited protocols fail to conform to
|
|
// themselves.
|
|
// FIXME: does this need a resolver?
|
|
for (auto proto : getInheritedProtocols(nullptr)) {
|
|
if (!proto->existentialConformsToSelf()) {
|
|
ProtocolDeclBits.ExistentialConformsToSelf = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ProtocolDecl::existentialTypeSupportedSlow(LazyResolver *resolver) {
|
|
// Assume for now that the existential type is supported; this
|
|
// prevents circularity issues.
|
|
ProtocolDeclBits.ExistentialTypeSupportedValid = true;
|
|
ProtocolDeclBits.ExistentialTypeSupported = true;
|
|
|
|
// Resolve the protocol's type.
|
|
if (resolver && !hasType())
|
|
resolver->resolveDeclSignature(this);
|
|
|
|
auto selfType = getProtocolSelf()->getArchetype();
|
|
for (auto member : getMembers()) {
|
|
if (auto vd = dyn_cast<ValueDecl>(member)) {
|
|
if (resolver && !vd->hasType())
|
|
resolver->resolveDeclSignature(vd);
|
|
}
|
|
|
|
if (member->isInvalid())
|
|
continue;
|
|
|
|
// Check for associated types.
|
|
if (isa<AssociatedTypeDecl>(member)) {
|
|
// An existential type cannot be used if the protocol has an
|
|
// associated type.
|
|
ProtocolDeclBits.ExistentialTypeSupported = false;
|
|
return false;
|
|
}
|
|
|
|
// For value members, look at their type signatures.
|
|
auto valueMember = dyn_cast<ValueDecl>(member);
|
|
if (!valueMember || !valueMember->hasType())
|
|
continue;
|
|
|
|
// Extract the type of the member, ignoring the 'self' parameter and return
|
|
// type of functions.
|
|
auto memberTy = valueMember->getType();
|
|
if (memberTy->is<ErrorType>())
|
|
continue;
|
|
if (isa<AbstractFunctionDecl>(valueMember)) {
|
|
// Drop the 'Self' parameter.
|
|
memberTy = memberTy->castTo<AnyFunctionType>()->getResult();
|
|
// Drop the return type. Methods are allowed to return Self.
|
|
memberTy = memberTy->castTo<AnyFunctionType>()->getInput();
|
|
}
|
|
|
|
// If we find 'Self' anywhere in the member's type, we cannot use the
|
|
// existential type.
|
|
if (memberTy.findIf([&](Type type) -> bool {
|
|
// If we found our archetype, return null.
|
|
if (auto archetype = type->getAs<ArchetypeType>()) {
|
|
return archetype == selfType;
|
|
}
|
|
|
|
return false;
|
|
})) {
|
|
ProtocolDeclBits.ExistentialTypeSupported = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check whether all of the inherited protocols can have existential
|
|
// types themselves.
|
|
for (auto proto : getInheritedProtocols(resolver)) {
|
|
if (!proto->existentialTypeSupported(resolver)) {
|
|
ProtocolDeclBits.ExistentialTypeSupported = false;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
StringRef ProtocolDecl::getObjCRuntimeName(
|
|
llvm::SmallVectorImpl<char> &buffer) const {
|
|
// If there is an 'objc' attribute with a name, use that name.
|
|
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
|
|
if (auto name = objc->getName())
|
|
return name->getString(buffer);
|
|
}
|
|
|
|
// Produce the mangled name for this protocol.
|
|
return mangleObjCRuntimeName(this, buffer);
|
|
}
|
|
|
|
GenericParamList *ProtocolDecl::createGenericParams(DeclContext *dc) {
|
|
SourceLoc loc;
|
|
if (auto ext = dyn_cast<ExtensionDecl>(dc))
|
|
loc = ext->getLoc();
|
|
else
|
|
loc = getLoc();
|
|
|
|
// Find the depth of the 'Self' parameter. This is zero in all valid
|
|
// code; however, we compute it nonetheless to maintain the AST
|
|
// invariants around generic parameter depths.
|
|
unsigned depth = 0;
|
|
GenericParamList *outerGenericParams
|
|
= dc->getParent()->getGenericParamsOfContext();
|
|
if (outerGenericParams)
|
|
depth = outerGenericParams->getDepth() + 1;
|
|
|
|
// The generic parameter 'Self'.
|
|
auto &ctx = getASTContext();
|
|
auto selfId = ctx.Id_Self;
|
|
auto selfDecl = new (ctx) GenericTypeParamDecl(dc, selfId, loc, depth, 0);
|
|
auto protoRef = new (ctx) SimpleIdentTypeRepr(loc, getName());
|
|
protoRef->setValue(this);
|
|
TypeLoc selfInherited[1] = { TypeLoc(protoRef) };
|
|
selfInherited[0].setType(ProtocolType::get(this, ctx));
|
|
selfDecl->setInherited(ctx.AllocateCopy(selfInherited));
|
|
selfDecl->setImplicit();
|
|
|
|
// The generic parameter list itself.
|
|
auto result = GenericParamList::create(ctx, SourceLoc(), selfDecl,
|
|
SourceLoc());
|
|
result->setOuterParameters(outerGenericParams);
|
|
return result;
|
|
}
|
|
|
|
/// \brief Return true if the 'getter' is mutating, i.e. that it requires an
|
|
/// lvalue base to be accessed.
|
|
bool AbstractStorageDecl::isGetterMutating() const {
|
|
switch (getStorageKind()) {
|
|
case AbstractStorageDecl::Stored:
|
|
return false;
|
|
|
|
case AbstractStorageDecl::StoredWithObservers:
|
|
case AbstractStorageDecl::StoredWithTrivialAccessors:
|
|
case AbstractStorageDecl::InheritedWithObservers:
|
|
case AbstractStorageDecl::ComputedWithMutableAddress:
|
|
case AbstractStorageDecl::Computed:
|
|
case AbstractStorageDecl::AddressedWithTrivialAccessors:
|
|
case AbstractStorageDecl::AddressedWithObservers:
|
|
assert(getGetter());
|
|
return getGetter()->isMutating();
|
|
|
|
case AbstractStorageDecl::Addressed:
|
|
assert(getAddressor());
|
|
return getAddressor()->isMutating();
|
|
}
|
|
}
|
|
|
|
/// \brief Return true if the 'setter' is nonmutating, i.e. that it can be
|
|
/// called even on an immutable base value.
|
|
bool AbstractStorageDecl::isSetterNonMutating() const {
|
|
// Setters declared in reference type contexts are never mutating.
|
|
if (auto contextType = getDeclContext()->getDeclaredTypeInContext()) {
|
|
if (contextType->hasReferenceSemantics())
|
|
return true;
|
|
}
|
|
|
|
switch (getStorageKind()) {
|
|
case AbstractStorageDecl::Stored:
|
|
case AbstractStorageDecl::StoredWithTrivialAccessors:
|
|
return false;
|
|
|
|
case AbstractStorageDecl::StoredWithObservers:
|
|
case AbstractStorageDecl::InheritedWithObservers:
|
|
case AbstractStorageDecl::Computed:
|
|
assert(getSetter());
|
|
return !getSetter()->isMutating();
|
|
|
|
case AbstractStorageDecl::Addressed:
|
|
case AbstractStorageDecl::AddressedWithTrivialAccessors:
|
|
case AbstractStorageDecl::AddressedWithObservers:
|
|
case AbstractStorageDecl::ComputedWithMutableAddress:
|
|
assert(getMutableAddressor());
|
|
return !getMutableAddressor()->isMutating();
|
|
}
|
|
llvm_unreachable("bad storage kind");
|
|
}
|
|
|
|
FuncDecl *AbstractStorageDecl::getAccessorFunction(AccessorKind kind) const {
|
|
switch (kind) {
|
|
case AccessorKind::IsGetter: return getGetter();
|
|
case AccessorKind::IsSetter: return getSetter();
|
|
case AccessorKind::IsMaterializeForSet: return getMaterializeForSetFunc();
|
|
case AccessorKind::IsAddressor: return getAddressor();
|
|
case AccessorKind::IsMutableAddressor: return getMutableAddressor();
|
|
case AccessorKind::IsDidSet: return getDidSetFunc();
|
|
case AccessorKind::IsWillSet: return getWillSetFunc();
|
|
case AccessorKind::NotAccessor: llvm_unreachable("called with NotAccessor");
|
|
}
|
|
llvm_unreachable("bad accessor kind!");
|
|
}
|
|
|
|
void AbstractStorageDecl::configureGetSetRecord(GetSetRecord *getSetInfo,
|
|
FuncDecl *getter,
|
|
FuncDecl *setter,
|
|
FuncDecl *materializeForSet) {
|
|
getSetInfo->Get = getter;
|
|
if (getter)
|
|
getter->makeAccessor(this, AccessorKind::IsGetter);
|
|
|
|
configureSetRecord(getSetInfo, setter, materializeForSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::configureSetRecord(GetSetRecord *getSetInfo,
|
|
FuncDecl *setter,
|
|
FuncDecl *materializeForSet) {
|
|
getSetInfo->Set = setter;
|
|
getSetInfo->MaterializeForSet = materializeForSet;
|
|
|
|
auto setSetterAccess = [&](FuncDecl *fn) {
|
|
if (auto setterAccess = GetSetInfo.getInt()) {
|
|
assert(!fn->hasAccessibility() ||
|
|
fn->getFormalAccess() == setterAccess.getValue());
|
|
fn->overwriteAccessibility(setterAccess.getValue());
|
|
}
|
|
};
|
|
|
|
if (setter) {
|
|
setter->makeAccessor(this, AccessorKind::IsSetter);
|
|
setSetterAccess(setter);
|
|
}
|
|
|
|
if (materializeForSet) {
|
|
materializeForSet->makeAccessor(this, AccessorKind::IsMaterializeForSet);
|
|
setSetterAccess(materializeForSet);
|
|
}
|
|
}
|
|
|
|
void AbstractStorageDecl::configureAddressorRecord(AddressorRecord *record,
|
|
FuncDecl *addressor,
|
|
FuncDecl *mutableAddressor) {
|
|
record->Address = addressor;
|
|
record->MutableAddress = mutableAddressor;
|
|
|
|
if (addressor) {
|
|
addressor->makeAccessor(this, AccessorKind::IsAddressor);
|
|
}
|
|
|
|
if (mutableAddressor) {
|
|
mutableAddressor->makeAccessor(this, AccessorKind::IsMutableAddressor);
|
|
}
|
|
}
|
|
|
|
void AbstractStorageDecl::configureObservingRecord(ObservingRecord *record,
|
|
FuncDecl *willSet,
|
|
FuncDecl *didSet) {
|
|
record->WillSet = willSet;
|
|
record->DidSet = didSet;
|
|
|
|
if (willSet) {
|
|
willSet->makeAccessor(this, AccessorKind::IsWillSet);
|
|
}
|
|
|
|
if (didSet) {
|
|
didSet->makeAccessor(this, AccessorKind::IsDidSet);
|
|
}
|
|
}
|
|
|
|
void AbstractStorageDecl::makeComputed(SourceLoc LBraceLoc,
|
|
FuncDecl *Get, FuncDecl *Set,
|
|
FuncDecl *MaterializeForSet,
|
|
SourceLoc RBraceLoc) {
|
|
assert(getStorageKind() == Stored && "StorageKind already set");
|
|
auto &Context = getASTContext();
|
|
void *Mem = Context.Allocate(sizeof(GetSetRecord), alignof(GetSetRecord));
|
|
auto *getSetInfo = new (Mem) GetSetRecord();
|
|
getSetInfo->Braces = SourceRange(LBraceLoc, RBraceLoc);
|
|
GetSetInfo.setPointer(getSetInfo);
|
|
configureGetSetRecord(getSetInfo, Get, Set, MaterializeForSet);
|
|
|
|
// Mark that this is a computed property.
|
|
setStorageKind(Computed);
|
|
}
|
|
|
|
void AbstractStorageDecl::setComputedSetter(FuncDecl *Set) {
|
|
assert(getStorageKind() == Computed && "Not a computed variable");
|
|
assert(getGetter() && "sanity check: missing getter");
|
|
assert(!getSetter() && "already has a setter");
|
|
assert(hasClangNode() && "should only be used for ObjC properties");
|
|
assert(Set && "should not be called for readonly properties");
|
|
GetSetInfo.getPointer()->Set = Set;
|
|
Set->makeAccessor(this, AccessorKind::IsSetter);
|
|
if (auto setterAccess = GetSetInfo.getInt()) {
|
|
assert(!Set->hasAccessibility() ||
|
|
Set->getFormalAccess() == setterAccess.getValue());
|
|
Set->overwriteAccessibility(setterAccess.getValue());
|
|
}
|
|
}
|
|
|
|
void AbstractStorageDecl::makeComputedWithMutableAddress(SourceLoc lbraceLoc,
|
|
FuncDecl *get, FuncDecl *set,
|
|
FuncDecl *materializeForSet,
|
|
FuncDecl *mutableAddressor,
|
|
SourceLoc rbraceLoc) {
|
|
assert(getStorageKind() == Stored && "StorageKind already set");
|
|
assert(get);
|
|
assert(mutableAddressor);
|
|
auto &ctx = getASTContext();
|
|
|
|
void *mem = ctx.Allocate(sizeof(GetSetRecordWithAddressors),
|
|
alignof(GetSetRecordWithAddressors));
|
|
auto info = new (mem) GetSetRecordWithAddressors();
|
|
info->Braces = SourceRange(lbraceLoc, rbraceLoc);
|
|
GetSetInfo.setPointer(info);
|
|
setStorageKind(ComputedWithMutableAddress);
|
|
|
|
configureAddressorRecord(info, nullptr, mutableAddressor);
|
|
configureGetSetRecord(info, get, set, materializeForSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::setMaterializeForSetFunc(FuncDecl *accessor) {
|
|
assert(hasAccessorFunctions() && "No accessors for declaration!");
|
|
assert(getSetter() && "declaration is not settable");
|
|
assert(!getMaterializeForSetFunc() && "already has a materializeForSet");
|
|
GetSetInfo.getPointer()->MaterializeForSet = accessor;
|
|
accessor->makeAccessor(this, AccessorKind::IsMaterializeForSet);
|
|
if (auto setterAccess = GetSetInfo.getInt()) {
|
|
assert(!accessor->hasAccessibility() ||
|
|
accessor->getFormalAccess() == setterAccess.getValue());
|
|
accessor->overwriteAccessibility(setterAccess.getValue());
|
|
}
|
|
}
|
|
|
|
/// \brief Turn this into a StoredWithTrivialAccessors var, specifying the
|
|
/// accessors (getter and setter) that go with it.
|
|
void AbstractStorageDecl::addTrivialAccessors(FuncDecl *Get,
|
|
FuncDecl *Set, FuncDecl *MaterializeForSet) {
|
|
assert((getStorageKind() == Stored ||
|
|
getStorageKind() == Addressed) && "StorageKind already set");
|
|
assert(Get);
|
|
|
|
auto &ctx = getASTContext();
|
|
GetSetRecord *getSetInfo;
|
|
if (getStorageKind() == Addressed) {
|
|
getSetInfo = GetSetInfo.getPointer();
|
|
setStorageKind(AddressedWithTrivialAccessors);
|
|
} else {
|
|
void *mem = ctx.Allocate(sizeof(GetSetRecord), alignof(GetSetRecord));
|
|
getSetInfo = new (mem) GetSetRecord();
|
|
getSetInfo->Braces = SourceRange();
|
|
GetSetInfo.setPointer(getSetInfo);
|
|
setStorageKind(StoredWithTrivialAccessors);
|
|
}
|
|
configureGetSetRecord(getSetInfo, Get, Set, MaterializeForSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::makeAddressed(SourceLoc lbraceLoc, FuncDecl *addressor,
|
|
FuncDecl *mutableAddressor,
|
|
SourceLoc rbraceLoc) {
|
|
assert(getStorageKind() == Stored && "StorageKind already set");
|
|
assert(addressor && "addressed mode, but no addressor function?");
|
|
|
|
auto &ctx = getASTContext();
|
|
|
|
void *mem = ctx.Allocate(sizeof(GetSetRecordWithAddressors),
|
|
alignof(GetSetRecordWithAddressors));
|
|
auto info = new (mem) GetSetRecordWithAddressors();
|
|
info->Braces = SourceRange(lbraceLoc, rbraceLoc);
|
|
GetSetInfo.setPointer(info);
|
|
setStorageKind(Addressed);
|
|
|
|
configureAddressorRecord(info, addressor, mutableAddressor);
|
|
}
|
|
|
|
void AbstractStorageDecl::makeStoredWithObservers(SourceLoc LBraceLoc,
|
|
FuncDecl *WillSet,
|
|
FuncDecl *DidSet,
|
|
SourceLoc RBraceLoc) {
|
|
assert(getStorageKind() == Stored && "VarDecl StorageKind already set");
|
|
assert((WillSet || DidSet) &&
|
|
"Can't be Observing without one or the other");
|
|
auto &Context = getASTContext();
|
|
void *Mem = Context.Allocate(sizeof(ObservingRecord),
|
|
alignof(ObservingRecord));
|
|
auto *observingInfo = new (Mem) ObservingRecord;
|
|
observingInfo->Braces = SourceRange(LBraceLoc, RBraceLoc);
|
|
GetSetInfo.setPointer(observingInfo);
|
|
|
|
// Mark that this is an observing property.
|
|
setStorageKind(StoredWithObservers);
|
|
|
|
configureObservingRecord(observingInfo, WillSet, DidSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::makeInheritedWithObservers(SourceLoc lbraceLoc,
|
|
FuncDecl *willSet,
|
|
FuncDecl *didSet,
|
|
SourceLoc rbraceLoc) {
|
|
assert(getStorageKind() == Stored && "StorageKind already set");
|
|
assert((willSet || didSet) &&
|
|
"Can't be Observing without one or the other");
|
|
auto &ctx = getASTContext();
|
|
void *mem = ctx.Allocate(sizeof(ObservingRecord), alignof(ObservingRecord));
|
|
auto *observingInfo = new (mem) ObservingRecord;
|
|
observingInfo->Braces = SourceRange(lbraceLoc, rbraceLoc);
|
|
GetSetInfo.setPointer(observingInfo);
|
|
|
|
// Mark that this is an observing property.
|
|
setStorageKind(InheritedWithObservers);
|
|
|
|
configureObservingRecord(observingInfo, willSet, didSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::makeAddressedWithObservers(SourceLoc lbraceLoc,
|
|
FuncDecl *addressor,
|
|
FuncDecl *mutableAddressor,
|
|
FuncDecl *willSet,
|
|
FuncDecl *didSet,
|
|
SourceLoc rbraceLoc) {
|
|
assert(getStorageKind() == Stored && "VarDecl StorageKind already set");
|
|
assert(addressor);
|
|
assert(mutableAddressor && "observing but immutable?");
|
|
assert((willSet || didSet) &&
|
|
"Can't be Observing without one or the other");
|
|
|
|
auto &ctx = getASTContext();
|
|
void *mem = ctx.Allocate(sizeof(ObservingRecordWithAddressors),
|
|
alignof(ObservingRecordWithAddressors));
|
|
auto info = new (mem) ObservingRecordWithAddressors();
|
|
info->Braces = SourceRange(lbraceLoc, rbraceLoc);
|
|
GetSetInfo.setPointer(info);
|
|
setStorageKind(AddressedWithObservers);
|
|
|
|
configureAddressorRecord(info, addressor, mutableAddressor);
|
|
configureObservingRecord(info, willSet, didSet);
|
|
}
|
|
|
|
/// \brief Specify the synthesized get/set functions for a Observing var.
|
|
/// This is used by Sema.
|
|
void AbstractStorageDecl::setObservingAccessors(FuncDecl *Get,
|
|
FuncDecl *Set,
|
|
FuncDecl *MaterializeForSet) {
|
|
assert(hasObservers() && "VarDecl is wrong type");
|
|
assert(!getGetter() && !getSetter() && "getter and setter already set");
|
|
assert(Get && Set && "Must specify getter and setter");
|
|
configureGetSetRecord(GetSetInfo.getPointer(), Get, Set, MaterializeForSet);
|
|
}
|
|
|
|
void AbstractStorageDecl::setInvalidBracesRange(SourceRange BracesRange) {
|
|
assert(!GetSetInfo.getPointer() && "Braces range has already been set");
|
|
|
|
auto &Context = getASTContext();
|
|
void *Mem = Context.Allocate(sizeof(GetSetRecord), alignof(GetSetRecord));
|
|
auto *getSetInfo = new (Mem) GetSetRecord();
|
|
getSetInfo->Braces = BracesRange;
|
|
getSetInfo->Get = nullptr;
|
|
getSetInfo->Set = nullptr;
|
|
getSetInfo->MaterializeForSet = nullptr;
|
|
GetSetInfo.setPointer(getSetInfo);
|
|
}
|
|
|
|
ObjCSelector AbstractStorageDecl::getObjCGetterSelector(
|
|
LazyResolver *resolver) const {
|
|
// If the getter has an @objc attribute with a name, use that.
|
|
if (auto getter = getGetter()) {
|
|
if (auto objcAttr = getter->getAttrs().getAttribute<ObjCAttr>()) {
|
|
if (auto name = objcAttr->getName())
|
|
return *name;
|
|
}
|
|
}
|
|
|
|
// Subscripts use a specific selector.
|
|
auto &ctx = getASTContext();
|
|
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
|
|
switch (SD->getObjCSubscriptKind(resolver)) {
|
|
case ObjCSubscriptKind::None:
|
|
llvm_unreachable("Not an Objective-C subscript");
|
|
case ObjCSubscriptKind::Indexed:
|
|
return ObjCSelector(ctx, 1, ctx.Id_objectAtIndexedSubscript);
|
|
case ObjCSubscriptKind::Keyed:
|
|
return ObjCSelector(ctx, 1, ctx.Id_objectForKeyedSubscript);
|
|
}
|
|
}
|
|
|
|
// The getter selector is the property name itself.
|
|
auto var = cast<VarDecl>(this);
|
|
return VarDecl::getDefaultObjCGetterSelector(ctx, var->getObjCPropertyName());
|
|
}
|
|
|
|
ObjCSelector AbstractStorageDecl::getObjCSetterSelector(
|
|
LazyResolver *resolver) const {
|
|
// If the setter has an @objc attribute with a name, use that.
|
|
auto setter = getSetter();
|
|
auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
|
|
: nullptr;
|
|
if (objcAttr) {
|
|
if (auto name = objcAttr->getName())
|
|
return *name;
|
|
}
|
|
|
|
// Subscripts use a specific selector.
|
|
auto &ctx = getASTContext();
|
|
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
|
|
switch (SD->getObjCSubscriptKind(resolver)) {
|
|
case ObjCSubscriptKind::None:
|
|
llvm_unreachable("Not an Objective-C subscript");
|
|
|
|
case ObjCSubscriptKind::Indexed:
|
|
return ObjCSelector(ctx, 2,
|
|
{ ctx.Id_setObject, ctx.Id_atIndexedSubscript });
|
|
case ObjCSubscriptKind::Keyed:
|
|
return ObjCSelector(ctx, 2,
|
|
{ ctx.Id_setObject, ctx.Id_forKeyedSubscript });
|
|
}
|
|
}
|
|
|
|
|
|
// The setter selector for, e.g., 'fooBar' is 'setFooBar:', with the
|
|
// property name capitalized and preceded by 'set'.
|
|
auto var = cast<VarDecl>(this);
|
|
auto result = VarDecl::getDefaultObjCSetterSelector(
|
|
ctx,
|
|
var->getObjCPropertyName());
|
|
|
|
// Cache the result, so we don't perform string manipulation again.
|
|
if (objcAttr)
|
|
const_cast<ObjCAttr *>(objcAttr)->setName(result, /*implicit=*/true);
|
|
|
|
return result;
|
|
}
|
|
|
|
SourceLoc AbstractStorageDecl::getOverrideLoc() const {
|
|
if (auto *Override = getAttrs().getAttribute<OverrideAttr>())
|
|
return Override->getLocation();
|
|
return SourceLoc();
|
|
}
|
|
|
|
static bool isSettable(const AbstractStorageDecl *decl) {
|
|
switch (decl->getStorageKind()) {
|
|
case AbstractStorageDecl::Stored:
|
|
return true;
|
|
|
|
case AbstractStorageDecl::StoredWithTrivialAccessors:
|
|
return decl->getSetter() != nullptr;
|
|
|
|
case AbstractStorageDecl::Addressed:
|
|
case AbstractStorageDecl::AddressedWithTrivialAccessors:
|
|
return decl->getMutableAddressor() != nullptr;
|
|
|
|
case AbstractStorageDecl::StoredWithObservers:
|
|
case AbstractStorageDecl::InheritedWithObservers:
|
|
case AbstractStorageDecl::AddressedWithObservers:
|
|
case AbstractStorageDecl::ComputedWithMutableAddress:
|
|
return true;
|
|
|
|
case AbstractStorageDecl::Computed:
|
|
return decl->getSetter() != nullptr;
|
|
}
|
|
llvm_unreachable("bad storage kind");
|
|
}
|
|
|
|
/// \brief Returns whether the var is settable in the specified context: this
|
|
/// is either because it is a stored var, because it has a custom setter, or
|
|
/// is a let member in an initializer.
|
|
bool VarDecl::isSettable(const DeclContext *UseDC,
|
|
const DeclRefExpr *base) const {
|
|
// If this is a 'var' decl, then we're settable if we have storage or a
|
|
// setter.
|
|
if (!isLet())
|
|
return ::isSettable(this);
|
|
|
|
// If the decl has a value bound to it but has no PBD, then it is
|
|
// initialized.
|
|
if (hasNonPatternBindingInit())
|
|
return false;
|
|
|
|
// 'let' parameters are never settable.
|
|
if (isa<ParamDecl>(this))
|
|
return false;
|
|
|
|
// Properties in structs/classes are only ever mutable in their designated
|
|
// initializer(s).
|
|
if (isInstanceMember()) {
|
|
auto *CD = dyn_cast_or_null<ConstructorDecl>(UseDC);
|
|
if (!CD) return false;
|
|
|
|
auto *CDC = CD->getDeclContext();
|
|
|
|
// If this init is defined inside of the same type (or in an extension
|
|
// thereof) as the let property, then it is mutable.
|
|
if (!CDC->isTypeContext() ||
|
|
CDC->getDeclaredTypeInContext()->getAnyNominal() !=
|
|
getDeclContext()->getDeclaredTypeInContext()->getAnyNominal())
|
|
return false;
|
|
|
|
if (base && CD->getImplicitSelfDecl() != base->getDecl())
|
|
return false;
|
|
|
|
// If this is a convenience initializer (i.e. one that calls
|
|
// self.init), then let properties are never mutable in it. They are
|
|
// only mutable in designated initializers.
|
|
if (CD->getDelegatingOrChainedInitKind(nullptr) ==
|
|
ConstructorDecl::BodyInitKind::Delegating)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// If the decl has an explicitly written initializer with a pattern binding,
|
|
// then it isn't settable.
|
|
if (getParentInitializer() != nullptr)
|
|
return false;
|
|
|
|
// Normal lets (e.g. globals) are only mutable in the context of the
|
|
// declaration. To handle top-level code properly, we look through
|
|
// the TopLevelCode decl on the use (if present) since the vardecl may be
|
|
// one level up.
|
|
if (getDeclContext() == UseDC)
|
|
return true;
|
|
|
|
if (UseDC && isa<TopLevelCodeDecl>(UseDC) &&
|
|
getDeclContext() == UseDC->getParent())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SubscriptDecl::isSettable() const {
|
|
return ::isSettable(this);
|
|
}
|
|
|
|
SourceRange VarDecl::getSourceRange() const {
|
|
if (auto Param = dyn_cast<ParamDecl>(this))
|
|
return Param->getSourceRange();
|
|
return getNameLoc();
|
|
}
|
|
|
|
SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const {
|
|
// For a parameter, map back to its parameter to get the TypeLoc.
|
|
if (auto *PD = dyn_cast<ParamDecl>(this)) {
|
|
if (auto typeRepr = PD->getTypeLoc().getTypeRepr())
|
|
return typeRepr->getSourceRange();
|
|
}
|
|
|
|
Pattern *Pat = getParentPattern();
|
|
if (!Pat || Pat->isImplicit())
|
|
return getSourceRange();
|
|
|
|
if (auto *VP = dyn_cast<VarPattern>(Pat))
|
|
Pat = VP->getSubPattern();
|
|
if (auto *TP = dyn_cast<TypedPattern>(Pat))
|
|
return TP->getTypeLoc().getTypeRepr()->getSourceRange();
|
|
return getSourceRange();
|
|
}
|
|
|
|
static bool isVarInPattern(const VarDecl *VD, Pattern *P) {
|
|
bool foundIt = false;
|
|
P->forEachVariable([&](VarDecl *FoundFD) {
|
|
foundIt |= FoundFD == VD;
|
|
});
|
|
return foundIt;
|
|
}
|
|
|
|
/// Return the Pattern involved in initializing this VarDecl. Recall that the
|
|
/// Pattern 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 or statement associated, it
|
|
/// returns null.
|
|
///
|
|
Pattern *VarDecl::getParentPattern() const {
|
|
// If this has a PatternBindingDecl parent, use its pattern.
|
|
if (auto *PBD = getParentPatternBinding())
|
|
return PBD->getPatternEntryForVarDecl(this).getPattern();
|
|
|
|
// If this is a statement parent, dig the pattern out of it.
|
|
if (auto *stmt = getParentPatternStmt()) {
|
|
if (auto *FES = dyn_cast<ForEachStmt>(stmt))
|
|
return FES->getPattern();
|
|
|
|
if (auto *CS = dyn_cast<CatchStmt>(stmt))
|
|
return CS->getErrorPattern();
|
|
|
|
if (auto *cs = dyn_cast<CaseStmt>(stmt)) {
|
|
// In a case statement, search for the pattern that contains it. This is
|
|
// a bit silly, because you can't have something like "case x, y:" anyway.
|
|
for (auto items : cs->getCaseLabelItems()) {
|
|
if (isVarInPattern(this, items.getPattern()))
|
|
return items.getPattern();
|
|
}
|
|
} else if (auto *LCS = dyn_cast<LabeledConditionalStmt>(stmt)) {
|
|
for (auto &elt : LCS->getCond())
|
|
if (auto pat = elt.getPatternOrNull())
|
|
if (isVarInPattern(this, pat))
|
|
return pat;
|
|
}
|
|
|
|
//stmt->dump();
|
|
assert(0 && "Unknown parent pattern statement?");
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool VarDecl::isSelfParameter() const {
|
|
// Note: we need to check the isImplicit() bit here to make sure that we
|
|
// don't classify explicit parameters declared with `self` as the self param.
|
|
return isa<ParamDecl>(this) && getName() == getASTContext().Id_self &&
|
|
isImplicit();
|
|
}
|
|
|
|
/// Return true if this stored property needs to be accessed with getters and
|
|
/// setters for Objective-C.
|
|
bool AbstractStorageDecl::hasObjCGetterAndSetter() const {
|
|
if (auto override = getOverriddenDecl())
|
|
return override->hasObjCGetterAndSetter();
|
|
|
|
if (!isObjC())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool AbstractStorageDecl::requiresObjCGetterAndSetter() const {
|
|
if (isFinal())
|
|
return false;
|
|
if (!hasObjCGetterAndSetter())
|
|
return false;
|
|
// Imported accessors are foreign and only have objc entry points.
|
|
if (hasClangNode())
|
|
return true;
|
|
// Otherwise, we only dispatch by @objc if the declaration is dynamic or
|
|
// NSManaged.
|
|
return getAttrs().hasAttribute<DynamicAttr>() ||
|
|
getAttrs().hasAttribute<NSManagedAttr>();
|
|
}
|
|
|
|
|
|
bool VarDecl::isAnonClosureParam() const {
|
|
auto name = getName();
|
|
if (name.empty())
|
|
return false;
|
|
|
|
auto nameStr = name.str();
|
|
if (nameStr.empty())
|
|
return false;
|
|
|
|
return nameStr[0] == '$';
|
|
}
|
|
|
|
StaticSpellingKind VarDecl::getCorrectStaticSpelling() const {
|
|
if (!isStatic())
|
|
return StaticSpellingKind::None;
|
|
|
|
return getCorrectStaticSpellingForDecl(this);
|
|
}
|
|
|
|
Identifier VarDecl::getObjCPropertyName() const {
|
|
if (auto attr = getAttrs().getAttribute<ObjCAttr>()) {
|
|
if (auto name = attr->getName())
|
|
return name->getSelectorPieces()[0];
|
|
}
|
|
|
|
return getName();
|
|
}
|
|
|
|
ObjCSelector VarDecl::getDefaultObjCGetterSelector(ASTContext &ctx,
|
|
Identifier propertyName) {
|
|
return ObjCSelector(ctx, 0, propertyName);
|
|
}
|
|
|
|
|
|
ObjCSelector VarDecl::getDefaultObjCSetterSelector(ASTContext &ctx,
|
|
Identifier propertyName) {
|
|
llvm::SmallString<16> scratch;
|
|
scratch += "set";
|
|
camel_case::appendSentenceCase(scratch, propertyName.str());
|
|
|
|
return ObjCSelector(ctx, 1, ctx.getIdentifier(scratch));
|
|
}
|
|
|
|
/// 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 VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const {
|
|
// If it isn't a 'let', don't touch it.
|
|
if (!isLet()) return;
|
|
|
|
// If this is the 'self' argument of a non-mutating method in a value type,
|
|
// suggest adding 'mutating' to the method.
|
|
if (isSelfParameter() && UseDC) {
|
|
// If the problematic decl is 'self', then we might be trying to mutate
|
|
// a property in a non-mutating method.
|
|
auto FD = dyn_cast<FuncDecl>(UseDC->getInnermostMethodContext());
|
|
if (FD && !FD->isMutating() && !FD->isImplicit() && FD->isInstanceMember()&&
|
|
!FD->getDeclContext()->getDeclaredTypeInContext()
|
|
->hasReferenceSemantics()) {
|
|
auto &d = getASTContext().Diags;
|
|
d.diagnose(FD->getFuncLoc(), diag::change_to_mutating, FD->isAccessor())
|
|
.fixItInsert(FD->getFuncLoc(), "mutating ");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Besides self, don't suggest mutability for explicit function parameters.
|
|
if (isa<ParamDecl>(this)) return;
|
|
|
|
// If this is a normal variable definition, then we can change 'let' to 'var'.
|
|
// We even are willing to suggest this for multi-variable binding, like
|
|
// "let (a,b) = "
|
|
// since the user has to choose to apply this anyway.
|
|
if (auto *PBD = getParentPatternBinding()) {
|
|
// Don't touch generated or invalid code.
|
|
if (PBD->getLoc().isInvalid() || PBD->isImplicit())
|
|
return;
|
|
|
|
auto &d = getASTContext().Diags;
|
|
d.diagnose(PBD->getLoc(), diag::convert_let_to_var)
|
|
.fixItReplace(PBD->getLoc(), "var");
|
|
return;
|
|
}
|
|
}
|
|
|
|
ParamDecl::ParamDecl(bool isLet, SourceLoc argumentNameLoc,
|
|
Identifier argumentName, SourceLoc parameterNameLoc,
|
|
Identifier parameterName, Type ty, DeclContext *dc)
|
|
: VarDecl(DeclKind::Param, /*IsStatic=*/false, isLet, parameterNameLoc,
|
|
parameterName, ty, dc),
|
|
ArgumentName(argumentName), ArgumentNameLoc(argumentNameLoc) {
|
|
}
|
|
|
|
/// Clone constructor, allocates a new ParamDecl identical to the first.
|
|
/// Intentionally not defined as a copy constructor to avoid accidental copies.
|
|
ParamDecl::ParamDecl(ParamDecl *PD)
|
|
: VarDecl(DeclKind::Param, /*IsStatic=*/false, PD->isLet(), PD->getNameLoc(),
|
|
PD->getName(), PD->hasType() ? PD->getType() : Type(),
|
|
PD->getDeclContext()),
|
|
ArgumentName(PD->getArgumentName()),
|
|
ArgumentNameLoc(PD->getArgumentNameLoc()),
|
|
typeLoc(PD->getTypeLoc()),
|
|
DefaultValueAndIsVariadic(PD->DefaultValueAndIsVariadic),
|
|
IsTypeLocImplicit(PD->IsTypeLocImplicit),
|
|
defaultArgumentKind(PD->defaultArgumentKind) {
|
|
}
|
|
|
|
|
|
/// \brief Retrieve the type of 'self' for the given context.
|
|
static Type getSelfTypeForContext(DeclContext *dc) {
|
|
// For a protocol or extension thereof, the type is 'Self'.
|
|
// FIXME: Weird that we're producing an archetype for protocol Self,
|
|
// but the declared type of the context in non-protocol cases.
|
|
if (dc->isProtocolOrProtocolExtensionContext()) {
|
|
// In the parser, generic parameters won't be wired up yet, just give up on
|
|
// producing a type.
|
|
if (dc->getGenericParamsOfContext() == nullptr)
|
|
return Type();
|
|
return dc->getProtocolSelf()->getArchetype();
|
|
}
|
|
return dc->getDeclaredTypeOfContext();
|
|
}
|
|
|
|
|
|
/// Create an implicit 'self' decl for a method in the specified decl context.
|
|
/// If 'static' is true, then this is self for a static method in the type.
|
|
///
|
|
/// Note that this decl is created, but it is returned with an incorrect
|
|
/// DeclContext that needs to be set correctly. This is automatically handled
|
|
/// when a function is created with this as part of its argument list.
|
|
///
|
|
ParamDecl *ParamDecl::createSelf(SourceLoc loc, DeclContext *DC,
|
|
bool isStaticMethod, bool isInOut) {
|
|
ASTContext &C = DC->getASTContext();
|
|
auto selfType = getSelfTypeForContext(DC);
|
|
|
|
// If we have a selfType (i.e. we're not in the parser before we know such
|
|
// things, configure it.
|
|
if (selfType) {
|
|
if (isStaticMethod)
|
|
selfType = MetatypeType::get(selfType);
|
|
|
|
if (isInOut)
|
|
selfType = InOutType::get(selfType);
|
|
}
|
|
|
|
auto *selfDecl = new (C) ParamDecl(/*IsLet*/!isInOut, SourceLoc(),
|
|
Identifier(), loc, C.Id_self, selfType,DC);
|
|
selfDecl->setImplicit();
|
|
return selfDecl;
|
|
}
|
|
|
|
/// Return the full source range of this parameter.
|
|
SourceRange ParamDecl::getSourceRange() const {
|
|
SourceRange range;
|
|
|
|
SourceLoc APINameLoc = getArgumentNameLoc();
|
|
SourceLoc nameLoc = getNameLoc();
|
|
|
|
if (APINameLoc.isValid() && nameLoc.isInvalid())
|
|
range = APINameLoc;
|
|
else if (APINameLoc.isInvalid() && nameLoc.isValid())
|
|
range = nameLoc;
|
|
else
|
|
range = SourceRange(APINameLoc, nameLoc);
|
|
|
|
if (range.isInvalid()) return range;
|
|
|
|
// It would be nice to extend the front of the range to show where inout is,
|
|
// but we don't have that location info. Extend the back of the range to the
|
|
// location of the default argument, or the typeloc if they are valid.
|
|
if (auto expr = getDefaultValue()) {
|
|
auto endLoc = expr->getExpr()->getEndLoc();
|
|
if (endLoc.isValid())
|
|
return SourceRange(range.Start, endLoc);
|
|
}
|
|
|
|
// If the typeloc has a valid location, use it to end the range.
|
|
if (auto typeRepr = getTypeLoc().getTypeRepr()) {
|
|
auto endLoc = typeRepr->getEndLoc();
|
|
if (endLoc.isValid())
|
|
return SourceRange(range.Start, endLoc);
|
|
}
|
|
|
|
// Otherwise, just return the info we have about the parameter.
|
|
return range;
|
|
}
|
|
|
|
Type ParamDecl::getVarargBaseTy(Type VarArgT) {
|
|
TypeBase *T = VarArgT.getPointer();
|
|
if (ArraySliceType *AT = dyn_cast<ArraySliceType>(T))
|
|
return AT->getBaseType();
|
|
if (BoundGenericType *BGT = dyn_cast<BoundGenericType>(T)) {
|
|
// It's the stdlib Array<T>.
|
|
return BGT->getGenericArgs()[0];
|
|
}
|
|
assert(isa<ErrorType>(T));
|
|
return T;
|
|
}
|
|
|
|
/// Determine whether the given Swift type is an integral type, i.e.,
|
|
/// a type that wraps a builtin integer.
|
|
static bool isIntegralType(Type type) {
|
|
// Consider structs in the standard library module that wrap a builtin
|
|
// integer type to be integral types.
|
|
if (auto structTy = type->getAs<StructType>()) {
|
|
auto structDecl = structTy->getDecl();
|
|
const DeclContext *DC = structDecl->getDeclContext();
|
|
if (!DC->isModuleScopeContext() || !DC->getParentModule()->isStdlibModule())
|
|
return false;
|
|
|
|
// Find the single ivar.
|
|
VarDecl *singleVar = nullptr;
|
|
for (auto member : structDecl->getStoredProperties()) {
|
|
if (singleVar)
|
|
return false;
|
|
singleVar = member;
|
|
}
|
|
|
|
if (!singleVar)
|
|
return false;
|
|
|
|
// Check whether it has integer type.
|
|
return singleVar->getType()->is<BuiltinIntegerType>();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void SubscriptDecl::setIndices(ParameterList *p) {
|
|
Indices = p;
|
|
|
|
if (Indices)
|
|
Indices->setDeclContextOfParamDecls(this);
|
|
}
|
|
|
|
Type SubscriptDecl::getIndicesType() const {
|
|
const auto type = getType();
|
|
if (type->is<ErrorType>())
|
|
return type;
|
|
return type->castTo<AnyFunctionType>()->getInput();
|
|
}
|
|
|
|
Type SubscriptDecl::getIndicesInterfaceType() const {
|
|
// FIXME: Unfortunate that we can't really capture the generic parameters
|
|
// here.
|
|
return getInterfaceType()->castTo<AnyFunctionType>()->getInput();
|
|
}
|
|
|
|
ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind(
|
|
LazyResolver *resolver) const {
|
|
auto indexTy = getIndicesType();
|
|
|
|
// Look through a named 1-tuple.
|
|
if (auto tupleTy = indexTy->getAs<TupleType>()) {
|
|
if (tupleTy->getNumElements() == 1 &&
|
|
!tupleTy->getElement(0).isVararg()) {
|
|
indexTy = tupleTy->getElementType(0);
|
|
}
|
|
}
|
|
|
|
// If the index type is an integral type, we have an indexed
|
|
// subscript.
|
|
if (isIntegralType(indexTy))
|
|
return ObjCSubscriptKind::Indexed;
|
|
|
|
// If the index type is an object type in Objective-C, we have a
|
|
// keyed subscript.
|
|
if (Type objectTy = indexTy->getAnyOptionalObjectType())
|
|
indexTy = objectTy;
|
|
|
|
if (getASTContext().getBridgedToObjC(getDeclContext(), indexTy, resolver))
|
|
return ObjCSubscriptKind::Keyed;
|
|
|
|
return ObjCSubscriptKind::None;
|
|
}
|
|
|
|
SourceRange SubscriptDecl::getSourceRange() const {
|
|
if (getBracesRange().isValid())
|
|
return { getSubscriptLoc(), getBracesRange().End };
|
|
return { getSubscriptLoc(), ElementTy.getSourceRange().End };
|
|
}
|
|
|
|
static Type getSelfTypeForContainer(AbstractFunctionDecl *theMethod,
|
|
bool isInitializingCtor,
|
|
bool wantInterfaceType) {
|
|
auto *dc = theMethod->getDeclContext();
|
|
|
|
// Determine the type of the container.
|
|
Type containerTy = wantInterfaceType ? dc->getDeclaredInterfaceType()
|
|
: dc->getDeclaredTypeInContext();
|
|
assert(containerTy && "stand alone functions don't have 'self'");
|
|
if (!containerTy) return Type();
|
|
|
|
bool isStatic = false;
|
|
bool isMutating = false;
|
|
Type selfTypeOverride;
|
|
|
|
if (auto *FD = dyn_cast<FuncDecl>(theMethod)) {
|
|
isStatic = FD->isStatic();
|
|
isMutating = FD->isMutating();
|
|
|
|
// The non-interface type of a method that returns DynamicSelf
|
|
// uses DynamicSelf for the type of 'self', which is important
|
|
// when type checking the body of the function.
|
|
if (!wantInterfaceType)
|
|
selfTypeOverride = FD->getDynamicSelf();
|
|
} else if (isa<ConstructorDecl>(theMethod)) {
|
|
if (isInitializingCtor) {
|
|
// initializing constructors of value types always have an implicitly
|
|
// inout self.
|
|
isMutating = true;
|
|
} else {
|
|
// allocating constructors have metatype 'self'.
|
|
isStatic = true;
|
|
}
|
|
} else if (isa<DestructorDecl>(theMethod)) {
|
|
// destructors of value types always have an implicitly inout self.
|
|
isMutating = true;
|
|
}
|
|
|
|
Type selfTy = selfTypeOverride;
|
|
if (!selfTy) {
|
|
// For a protocol, the type of 'self' is the parameter type 'Self', not
|
|
// the protocol itself.
|
|
selfTy = containerTy;
|
|
if (containerTy->is<ProtocolType>()) {
|
|
auto self = dc->getProtocolSelf();
|
|
assert(self && "Missing 'Self' type in protocol");
|
|
if (wantInterfaceType)
|
|
selfTy = self->getDeclaredType();
|
|
else
|
|
selfTy = self->getArchetype();
|
|
}
|
|
}
|
|
|
|
// If the self type couldn't be computed, or is the result of an
|
|
// upstream error, return an error type.
|
|
if (!selfTy || selfTy->is<ErrorType>())
|
|
return ErrorType::get(dc->getASTContext());
|
|
|
|
// 'static' functions have 'self' of type metatype<T>.
|
|
if (isStatic)
|
|
return MetatypeType::get(selfTy, dc->getASTContext());
|
|
|
|
// Reference types have 'self' of type T.
|
|
if (containerTy->hasReferenceSemantics())
|
|
return selfTy;
|
|
|
|
// Mutating methods are always passed inout so we can receive the side
|
|
// effect.
|
|
if (isMutating)
|
|
return InOutType::get(selfTy);
|
|
|
|
// Nonmutating methods on structs and enums pass the receiver by value.
|
|
return selfTy;
|
|
}
|
|
|
|
DeclName AbstractFunctionDecl::getEffectiveFullName() const {
|
|
if (getFullName())
|
|
return getFullName();
|
|
|
|
if (auto func = dyn_cast<FuncDecl>(this)) {
|
|
if (auto afd = func->getAccessorStorageDecl()) {
|
|
auto &ctx = getASTContext();
|
|
auto subscript = dyn_cast<SubscriptDecl>(afd);
|
|
switch (auto accessorKind = func->getAccessorKind()) {
|
|
case AccessorKind::NotAccessor:
|
|
break;
|
|
|
|
// These don't have any extra implicit parameters.
|
|
case AccessorKind::IsAddressor:
|
|
case AccessorKind::IsMutableAddressor:
|
|
case AccessorKind::IsGetter:
|
|
return subscript ? subscript->getFullName()
|
|
: DeclName(ctx, afd->getName(),
|
|
ArrayRef<Identifier>());
|
|
|
|
case AccessorKind::IsSetter:
|
|
case AccessorKind::IsMaterializeForSet:
|
|
case AccessorKind::IsDidSet:
|
|
case AccessorKind::IsWillSet: {
|
|
SmallVector<Identifier, 4> argNames;
|
|
// The implicit value/buffer parameter.
|
|
argNames.push_back(Identifier());
|
|
// The callback storage parameter on materializeForSet.
|
|
if (accessorKind == AccessorKind::IsMaterializeForSet)
|
|
argNames.push_back(Identifier());
|
|
// The subscript index parameters.
|
|
if (subscript) {
|
|
argNames.append(subscript->getFullName().getArgumentNames().begin(),
|
|
subscript->getFullName().getArgumentNames().end());
|
|
}
|
|
return DeclName(ctx, afd->getName(), argNames);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return DeclName();
|
|
}
|
|
|
|
void AbstractFunctionDecl::setGenericParams(GenericParamList *GP) {
|
|
// Set the specified generic parameters onto this abstract function, setting
|
|
// the parameters' context to the function along the way.
|
|
GenericParams = GP;
|
|
if (GP)
|
|
for (auto Param : *GP)
|
|
Param->setDeclContext(this);
|
|
}
|
|
|
|
|
|
Type AbstractFunctionDecl::computeSelfType() {
|
|
return getSelfTypeForContainer(this, true, false);
|
|
}
|
|
|
|
Type AbstractFunctionDecl::computeInterfaceSelfType(bool isInitializingCtor) {
|
|
return getSelfTypeForContainer(this, isInitializingCtor, true);
|
|
}
|
|
|
|
/// \brief This method returns the implicit 'self' decl.
|
|
///
|
|
/// Note that some functions don't have an implicit 'self' decl, for example,
|
|
/// free functions. In this case nullptr is returned.
|
|
ParamDecl *AbstractFunctionDecl::getImplicitSelfDecl() {
|
|
auto paramLists = getParameterLists();
|
|
if (paramLists.empty())
|
|
return nullptr;
|
|
|
|
// "self" is always the first parameter list.
|
|
if (paramLists[0]->size() == 1 && paramLists[0]->get(0)->isSelfParameter())
|
|
return paramLists[0]->get(0);
|
|
return nullptr;
|
|
}
|
|
|
|
Type AbstractFunctionDecl::getExtensionType() const {
|
|
return getDeclContext()->getDeclaredTypeInContext();
|
|
}
|
|
|
|
std::pair<DefaultArgumentKind, Type>
|
|
AbstractFunctionDecl::getDefaultArg(unsigned Index) const {
|
|
auto paramLists = getParameterLists();
|
|
|
|
if (getImplicitSelfDecl()) // Skip the 'self' parameter; it is not counted.
|
|
paramLists = paramLists.slice(1);
|
|
|
|
for (auto paramList : paramLists) {
|
|
if (Index < paramList->size()) {
|
|
auto param = paramList->get(Index);
|
|
return { param->getDefaultArgumentKind(), param->getType() };
|
|
}
|
|
|
|
Index -= paramList->size();
|
|
}
|
|
|
|
llvm_unreachable("Invalid parameter index");
|
|
}
|
|
|
|
bool AbstractFunctionDecl::argumentNameIsAPIByDefault(unsigned i) const {
|
|
// Initializers have argument labels.
|
|
if (isa<ConstructorDecl>(this))
|
|
return true;
|
|
|
|
if (auto func = dyn_cast<FuncDecl>(this)) {
|
|
// Operators do not have argument labels.
|
|
if (func->isOperator())
|
|
return false;
|
|
|
|
// Other functions have argument labels for every argument after the first.
|
|
return i > 0;
|
|
}
|
|
|
|
assert(isa<DestructorDecl>(this));
|
|
return false;
|
|
}
|
|
|
|
SourceRange AbstractFunctionDecl::getBodySourceRange() const {
|
|
switch (getBodyKind()) {
|
|
case BodyKind::None:
|
|
case BodyKind::MemberwiseInitializer:
|
|
return SourceRange();
|
|
|
|
case BodyKind::Parsed:
|
|
case BodyKind::Synthesize:
|
|
case BodyKind::TypeChecked:
|
|
if (auto body = getBody())
|
|
return body->getSourceRange();
|
|
|
|
return SourceRange();
|
|
|
|
case BodyKind::Skipped:
|
|
case BodyKind::Unparsed:
|
|
return BodyRange;
|
|
}
|
|
llvm_unreachable("bad BodyKind");
|
|
}
|
|
|
|
SourceRange AbstractFunctionDecl::getSignatureSourceRange() const {
|
|
if (isImplicit())
|
|
return SourceRange();
|
|
|
|
auto paramLists = getParameterLists();
|
|
if (paramLists.empty())
|
|
return getNameLoc();
|
|
|
|
for (auto *paramList : reversed(paramLists)) {
|
|
auto endLoc = paramList->getSourceRange().End;
|
|
if (endLoc.isValid())
|
|
return SourceRange(getNameLoc(), endLoc);
|
|
}
|
|
return getNameLoc();
|
|
}
|
|
|
|
ObjCSelector AbstractFunctionDecl::getObjCSelector(
|
|
LazyResolver *resolver) const {
|
|
// If there is an @objc attribute with a name, use that name.
|
|
auto objc = getAttrs().getAttribute<ObjCAttr>();
|
|
if (objc) {
|
|
if (auto name = objc->getName())
|
|
return *name;
|
|
}
|
|
|
|
auto &ctx = getASTContext();
|
|
auto argNames = getFullName().getArgumentNames();
|
|
|
|
auto func = dyn_cast<FuncDecl>(this);
|
|
if (func) {
|
|
// For a getter or setter, go through the variable or subscript decl.
|
|
if (func->isGetterOrSetter()) {
|
|
auto asd = cast<AbstractStorageDecl>(func->getAccessorStorageDecl());
|
|
return func->isGetter() ? asd->getObjCGetterSelector(resolver)
|
|
: asd->getObjCSetterSelector(resolver);
|
|
}
|
|
}
|
|
|
|
// Deinitializers are always called "dealloc".
|
|
if (isa<DestructorDecl>(this)) {
|
|
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
|
|
}
|
|
|
|
|
|
// If this is a zero-parameter initializer with a long selector
|
|
// name, form that selector.
|
|
auto ctor = dyn_cast<ConstructorDecl>(this);
|
|
if (ctor && ctor->isObjCZeroParameterWithLongSelector()) {
|
|
Identifier firstName = argNames[0];
|
|
llvm::SmallString<16> scratch;
|
|
scratch += "init";
|
|
|
|
// If the first argument name doesn't start with a preposition, add "with".
|
|
if (getPrepositionKind(camel_case::getFirstWord(firstName.str()))
|
|
== PK_None) {
|
|
camel_case::appendSentenceCase(scratch, "With");
|
|
}
|
|
|
|
camel_case::appendSentenceCase(scratch, firstName.str());
|
|
return ObjCSelector(ctx, 0, ctx.getIdentifier(scratch));
|
|
}
|
|
|
|
// The number of selector pieces we'll have.
|
|
Optional<ForeignErrorConvention> errorConvention
|
|
= getForeignErrorConvention();
|
|
unsigned numSelectorPieces
|
|
= argNames.size() + (errorConvention.hasValue() ? 1 : 0);
|
|
|
|
// If we have no arguments, it's a nullary selector.
|
|
if (numSelectorPieces == 0) {
|
|
return ObjCSelector(ctx, 0, getName());
|
|
}
|
|
|
|
// If it's a unary selector with no name for the first argument, we're done.
|
|
if (numSelectorPieces == 1 && argNames.size() == 1 && argNames[0].empty()) {
|
|
return ObjCSelector(ctx, 1, getName());
|
|
}
|
|
|
|
/// Collect the selector pieces.
|
|
SmallVector<Identifier, 4> selectorPieces;
|
|
selectorPieces.reserve(numSelectorPieces);
|
|
bool didStringManipulation = false;
|
|
unsigned argIndex = 0;
|
|
for (unsigned piece = 0; piece != numSelectorPieces; ++piece) {
|
|
if (piece > 0) {
|
|
// If we have an error convention that inserts an error parameter
|
|
// here, add "error".
|
|
if (errorConvention &&
|
|
piece == errorConvention->getErrorParameterIndex()) {
|
|
selectorPieces.push_back(ctx.Id_error);
|
|
continue;
|
|
}
|
|
|
|
// Selector pieces beyond the first are simple.
|
|
selectorPieces.push_back(argNames[argIndex++]);
|
|
continue;
|
|
}
|
|
|
|
// For the first selector piece, attach either the first parameter
|
|
// or "AndReturnError" to the base name, if appropriate.
|
|
auto firstPiece = getName();
|
|
llvm::SmallString<32> scratch;
|
|
scratch += firstPiece.str();
|
|
if (errorConvention && piece == errorConvention->getErrorParameterIndex()) {
|
|
// The error is first; append "AndReturnError".
|
|
camel_case::appendSentenceCase(scratch, "AndReturnError");
|
|
|
|
firstPiece = ctx.getIdentifier(scratch);
|
|
didStringManipulation = true;
|
|
} else if (!argNames[argIndex].empty()) {
|
|
// If the first argument name doesn't start with a preposition, and the
|
|
// method name doesn't end with a preposition, add "with".
|
|
auto firstName = argNames[argIndex++];
|
|
if (getPrepositionKind(camel_case::getFirstWord(firstName.str()))
|
|
== PK_None &&
|
|
getPrepositionKind(camel_case::getLastWord(firstPiece.str()))
|
|
== PK_None) {
|
|
camel_case::appendSentenceCase(scratch, "With");
|
|
}
|
|
|
|
camel_case::appendSentenceCase(scratch, firstName.str());
|
|
firstPiece = ctx.getIdentifier(scratch);
|
|
didStringManipulation = true;
|
|
} else {
|
|
++argIndex;
|
|
}
|
|
|
|
selectorPieces.push_back(firstPiece);
|
|
}
|
|
assert(argIndex == argNames.size());
|
|
|
|
// Form the result.
|
|
auto result = ObjCSelector(ctx, selectorPieces.size(), selectorPieces);
|
|
|
|
// If we did any string manipulation, cache the result. We don't want to
|
|
// do that again.
|
|
if (didStringManipulation && objc)
|
|
const_cast<ObjCAttr *>(objc)->setName(result, /*implicit=*/true);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool AbstractFunctionDecl::isObjCInstanceMethod() const {
|
|
return isInstanceMember() || isa<ConstructorDecl>(this);
|
|
}
|
|
|
|
AbstractFunctionDecl *AbstractFunctionDecl::getOverriddenDecl() const {
|
|
if (auto func = dyn_cast<FuncDecl>(this))
|
|
return func->getOverriddenDecl();
|
|
if (auto ctor = dyn_cast<ConstructorDecl>(this))
|
|
return ctor->getOverriddenDecl();
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
FuncDecl *FuncDecl::createImpl(ASTContext &Context,
|
|
SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
SourceLoc ThrowsLoc,
|
|
SourceLoc AccessorKeywordLoc,
|
|
GenericParamList *GenericParams,
|
|
Type Ty, unsigned NumParamPatterns,
|
|
DeclContext *Parent,
|
|
ClangNode ClangN) {
|
|
assert(NumParamPatterns > 0);
|
|
size_t Size = sizeof(FuncDecl) + NumParamPatterns * sizeof(Pattern *);
|
|
void *DeclPtr = allocateMemoryForDecl<FuncDecl>(Context, Size,
|
|
!ClangN.isNull());
|
|
auto D = ::new (DeclPtr)
|
|
FuncDecl(StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, ThrowsLoc,
|
|
AccessorKeywordLoc, NumParamPatterns, GenericParams, Ty, Parent);
|
|
if (ClangN)
|
|
D->setClangNode(ClangN);
|
|
return D;
|
|
}
|
|
|
|
FuncDecl *FuncDecl::createDeserialized(ASTContext &Context,
|
|
SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc,
|
|
DeclName Name, SourceLoc NameLoc,
|
|
SourceLoc ThrowsLoc,
|
|
SourceLoc AccessorKeywordLoc,
|
|
GenericParamList *GenericParams,
|
|
Type Ty, unsigned NumParamPatterns,
|
|
DeclContext *Parent) {
|
|
return createImpl(Context, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc,
|
|
ThrowsLoc, AccessorKeywordLoc, GenericParams, Ty,
|
|
NumParamPatterns, Parent, ClangNode());
|
|
}
|
|
|
|
FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc,
|
|
StaticSpellingKind StaticSpelling,
|
|
SourceLoc FuncLoc, DeclName Name,
|
|
SourceLoc NameLoc, SourceLoc ThrowsLoc,
|
|
SourceLoc AccessorKeywordLoc,
|
|
GenericParamList *GenericParams,
|
|
Type Ty, ArrayRef<ParameterList*> BodyParams,
|
|
TypeLoc FnRetType, DeclContext *Parent,
|
|
ClangNode ClangN) {
|
|
const unsigned NumParamPatterns = BodyParams.size();
|
|
auto *FD = FuncDecl::createImpl(
|
|
Context, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, ThrowsLoc,
|
|
AccessorKeywordLoc, GenericParams, Ty, NumParamPatterns, Parent, ClangN);
|
|
FD->setDeserializedSignature(BodyParams, FnRetType);
|
|
return FD;
|
|
}
|
|
|
|
StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const {
|
|
assert(getDeclContext()->isTypeContext());
|
|
if (!isStatic())
|
|
return StaticSpellingKind::None;
|
|
|
|
return getCorrectStaticSpellingForDecl(this);
|
|
}
|
|
|
|
bool FuncDecl::isExplicitNonMutating() const {
|
|
return !isMutating() &&
|
|
isAccessor() && !isGetter() &&
|
|
isInstanceMember() &&
|
|
!getDeclContext()->getDeclaredTypeInContext()->hasReferenceSemantics();
|
|
}
|
|
|
|
void FuncDecl::setDeserializedSignature(ArrayRef<ParameterList *> BodyParams,
|
|
TypeLoc FnRetType) {
|
|
MutableArrayRef<ParameterList *> BodyParamsRef = getParameterLists();
|
|
unsigned NumParamPatterns = BodyParamsRef.size();
|
|
|
|
#ifndef NDEBUG
|
|
unsigned NumParams = BodyParams[getDeclContext()->isTypeContext()]->size();
|
|
auto Name = getFullName();
|
|
assert((!Name || !Name.isSimpleName()) && "Must have a simple name");
|
|
assert(!Name || (Name.getArgumentNames().size() == NumParams));
|
|
#endif
|
|
|
|
for (unsigned i = 0; i != NumParamPatterns; ++i)
|
|
BodyParamsRef[i] = BodyParams[i];
|
|
|
|
// Set the decl context of any vardecls to this FuncDecl.
|
|
for (auto P : BodyParams)
|
|
if (P)
|
|
P->setDeclContextOfParamDecls(this);
|
|
|
|
this->FnRetType = FnRetType;
|
|
}
|
|
|
|
Type FuncDecl::getResultType() const {
|
|
if (!hasType())
|
|
return nullptr;
|
|
|
|
Type resultTy = getType();
|
|
if (resultTy->is<ErrorType>())
|
|
return resultTy;
|
|
|
|
for (unsigned i = 0, e = getNaturalArgumentCount(); i != e; ++i)
|
|
resultTy = resultTy->castTo<AnyFunctionType>()->getResult();
|
|
|
|
if (!resultTy)
|
|
resultTy = TupleType::getEmpty(getASTContext());
|
|
|
|
return resultTy;
|
|
}
|
|
|
|
bool AbstractFunctionDecl::isBodyThrowing() const {
|
|
if (!hasType())
|
|
return false;
|
|
|
|
Type type = getType();
|
|
if (type->is<ErrorType>())
|
|
return false;
|
|
|
|
auto fnTy = type->castTo<AnyFunctionType>();
|
|
for (unsigned i = 1, e = getNaturalArgumentCount(); i != e; ++i)
|
|
fnTy = fnTy->getResult()->castTo<AnyFunctionType>();
|
|
|
|
return fnTy->getExtInfo().throws();
|
|
}
|
|
|
|
bool FuncDecl::isUnaryOperator() const {
|
|
if (!isOperator())
|
|
return false;
|
|
|
|
unsigned opArgIndex
|
|
= getDeclContext()->isProtocolOrProtocolExtensionContext() ? 1 : 0;
|
|
|
|
auto *params = getParameterList(opArgIndex);
|
|
return params->size() == 1 && !params->get(0)->isVariadic();
|
|
}
|
|
|
|
bool FuncDecl::isBinaryOperator() const {
|
|
if (!isOperator())
|
|
return false;
|
|
|
|
unsigned opArgIndex
|
|
= getDeclContext()->isProtocolOrProtocolExtensionContext() ? 1 : 0;
|
|
|
|
auto *params = getParameterList(opArgIndex);
|
|
return params->size() == 2 && !params->get(1)->isVariadic();
|
|
}
|
|
|
|
ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc,
|
|
OptionalTypeKind Failability,
|
|
SourceLoc FailabilityLoc,
|
|
ParamDecl *selfDecl,
|
|
ParameterList *BodyParams,
|
|
GenericParamList *GenericParams,
|
|
SourceLoc throwsLoc,
|
|
DeclContext *Parent)
|
|
: AbstractFunctionDecl(DeclKind::Constructor, Parent, Name,
|
|
ConstructorLoc, 2, GenericParams),
|
|
FailabilityLoc(FailabilityLoc), ThrowsLoc(throwsLoc)
|
|
{
|
|
setParameterLists(selfDecl, BodyParams);
|
|
|
|
ConstructorDeclBits.ComputedBodyInitKind = 0;
|
|
ConstructorDeclBits.InitKind
|
|
= static_cast<unsigned>(CtorInitializerKind::Designated);
|
|
ConstructorDeclBits.HasStubImplementation = 0;
|
|
this->Failability = static_cast<unsigned>(Failability);
|
|
}
|
|
|
|
void ConstructorDecl::setParameterLists(ParamDecl *selfDecl,
|
|
ParameterList *bodyParams) {
|
|
if (selfDecl) {
|
|
ParameterLists[0] = ParameterList::createWithoutLoc(selfDecl);
|
|
ParameterLists[0]->setDeclContextOfParamDecls(this);
|
|
} else {
|
|
ParameterLists[0] = nullptr;
|
|
}
|
|
|
|
ParameterLists[1] = bodyParams;
|
|
if (bodyParams)
|
|
bodyParams->setDeclContextOfParamDecls(this);
|
|
|
|
assert(!getFullName().isSimpleName() && "Constructor name must be compound");
|
|
assert(!bodyParams ||
|
|
(getFullName().getArgumentNames().size() == bodyParams->size()));
|
|
}
|
|
|
|
bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const {
|
|
// The initializer must have a single, non-empty argument name.
|
|
if (getFullName().getArgumentNames().size() != 1 ||
|
|
getFullName().getArgumentNames()[0].empty())
|
|
return false;
|
|
|
|
auto *params = getParameterList(1);
|
|
if (params->size() != 1)
|
|
return false;
|
|
|
|
return params->get(0)->getType()->isVoid();
|
|
}
|
|
|
|
DestructorDecl::DestructorDecl(Identifier NameHack, SourceLoc DestructorLoc,
|
|
ParamDecl *selfDecl, DeclContext *Parent)
|
|
: AbstractFunctionDecl(DeclKind::Destructor, Parent, NameHack,
|
|
DestructorLoc, 1, nullptr) {
|
|
setSelfDecl(selfDecl);
|
|
}
|
|
|
|
void DestructorDecl::setSelfDecl(ParamDecl *selfDecl) {
|
|
if (selfDecl) {
|
|
SelfParameter = ParameterList::createWithoutLoc(selfDecl);
|
|
SelfParameter->setDeclContextOfParamDecls(this);
|
|
} else {
|
|
SelfParameter = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
DynamicSelfType *FuncDecl::getDynamicSelf() const {
|
|
if (!hasDynamicSelf())
|
|
return nullptr;
|
|
|
|
auto extType = getExtensionType();
|
|
if (extType->is<ProtocolType>())
|
|
return DynamicSelfType::get(getDeclContext()->getProtocolSelf()
|
|
->getArchetype(),
|
|
getASTContext());
|
|
|
|
return DynamicSelfType::get(extType, getASTContext());
|
|
}
|
|
|
|
DynamicSelfType *FuncDecl::getDynamicSelfInterface() const {
|
|
if (!hasDynamicSelf())
|
|
return nullptr;
|
|
|
|
auto extType = getDeclContext()->getDeclaredInterfaceType();
|
|
if (extType->is<ProtocolType>())
|
|
return DynamicSelfType::get(getDeclContext()->getProtocolSelf()
|
|
->getDeclaredType(),
|
|
getASTContext());
|
|
|
|
return DynamicSelfType::get(extType, getASTContext());
|
|
}
|
|
|
|
bool FuncDecl::hasArchetypeSelf() const {
|
|
if (!getDeclContext()->isProtocolExtensionContext())
|
|
return false;
|
|
|
|
auto selfTy = getDeclContext()->getProtocolSelf()->getArchetype();
|
|
|
|
auto resultTy = getResultType();
|
|
auto optionalResultTy = resultTy->getAnyOptionalObjectType();
|
|
if (optionalResultTy)
|
|
return optionalResultTy->isEqual(selfTy);
|
|
return resultTy->isEqual(selfTy);
|
|
}
|
|
|
|
SourceRange FuncDecl::getSourceRange() const {
|
|
SourceLoc StartLoc = getStartLoc();
|
|
if (StartLoc.isInvalid()) return SourceRange();
|
|
|
|
if (getBodyKind() == BodyKind::Unparsed ||
|
|
getBodyKind() == BodyKind::Skipped)
|
|
return { StartLoc, BodyRange.End };
|
|
|
|
if (auto *B = getBody())
|
|
return { StartLoc, B->getEndLoc() };
|
|
if (getBodyResultTypeLoc().hasLocation() &&
|
|
getBodyResultTypeLoc().getSourceRange().End.isValid() &&
|
|
!this->isAccessor())
|
|
return { StartLoc, getBodyResultTypeLoc().getSourceRange().End };
|
|
auto LastParamListEndLoc = getParameterLists().back()->getSourceRange().End;
|
|
if (LastParamListEndLoc.isValid())
|
|
return { StartLoc, LastParamListEndLoc };
|
|
return StartLoc;
|
|
}
|
|
|
|
SourceRange EnumElementDecl::getSourceRange() const {
|
|
if (RawValueExpr && !RawValueExpr->isImplicit())
|
|
return {getStartLoc(), RawValueExpr->getEndLoc()};
|
|
if (ArgumentType.hasLocation())
|
|
return {getStartLoc(), ArgumentType.getSourceRange().End};
|
|
return {getStartLoc(), getNameLoc()};
|
|
}
|
|
|
|
void EnumElementDecl::computeType() {
|
|
EnumDecl *ED = getParentEnum();
|
|
|
|
Type resultTy = ED->getDeclaredTypeInContext();
|
|
Type argTy = MetatypeType::get(resultTy);
|
|
|
|
// The type of the enum element is either (T) -> T or (T) -> ArgType -> T.
|
|
if (getArgumentType())
|
|
resultTy = FunctionType::get(getArgumentType(), resultTy);
|
|
|
|
if (ED->isGenericTypeContext())
|
|
resultTy = PolymorphicFunctionType::get(argTy, resultTy,
|
|
ED->getGenericParamsOfContext());
|
|
else
|
|
resultTy = FunctionType::get(argTy, resultTy);
|
|
|
|
setType(resultTy);
|
|
}
|
|
|
|
Type EnumElementDecl::getArgumentInterfaceType() const {
|
|
if (!hasArgumentType())
|
|
return nullptr;
|
|
|
|
auto interfaceType = getInterfaceType();
|
|
if (interfaceType->is<ErrorType>()) {
|
|
return interfaceType;
|
|
}
|
|
|
|
auto funcTy = interfaceType->castTo<AnyFunctionType>();
|
|
funcTy = funcTy->getResult()->castTo<AnyFunctionType>();
|
|
return funcTy->getInput();
|
|
}
|
|
|
|
EnumCaseDecl *EnumElementDecl::getParentCase() const {
|
|
for (EnumCaseDecl *EC : getParentEnum()->getAllCases()) {
|
|
ArrayRef<EnumElementDecl *> CaseElements = EC->getElements();
|
|
if (std::find(CaseElements.begin(), CaseElements.end(), this) !=
|
|
CaseElements.end()) {
|
|
return EC;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("enum element not in case of parent enum");
|
|
}
|
|
|
|
SourceRange ConstructorDecl::getSourceRange() const {
|
|
if (isImplicit())
|
|
return getConstructorLoc();
|
|
|
|
if (getBodyKind() == BodyKind::Unparsed ||
|
|
getBodyKind() == BodyKind::Skipped)
|
|
return { getConstructorLoc(), BodyRange.End };
|
|
|
|
SourceLoc End;
|
|
if (auto body = getBody())
|
|
End = body->getEndLoc();
|
|
if (End.isInvalid())
|
|
End = getSignatureSourceRange().End;
|
|
|
|
return { getConstructorLoc(), End };
|
|
}
|
|
|
|
Type ConstructorDecl::getArgumentType() const {
|
|
Type ArgTy = getType();
|
|
ArgTy = ArgTy->castTo<AnyFunctionType>()->getResult();
|
|
ArgTy = ArgTy->castTo<AnyFunctionType>()->getInput();
|
|
return ArgTy;
|
|
}
|
|
|
|
Type ConstructorDecl::getResultType() const {
|
|
Type ArgTy = getType();
|
|
ArgTy = ArgTy->castTo<AnyFunctionType>()->getResult();
|
|
ArgTy = ArgTy->castTo<AnyFunctionType>()->getResult();
|
|
return ArgTy;
|
|
}
|
|
|
|
Type ConstructorDecl::getInitializerInterfaceType() {
|
|
if (!InitializerInterfaceType) {
|
|
assert((!InitializerType || !InitializerType->is<PolymorphicFunctionType>())
|
|
&& "polymorphic function type is invalid interface type");
|
|
|
|
// Don't cache type variable types.
|
|
if (InitializerType->hasTypeVariable())
|
|
return InitializerType;
|
|
|
|
InitializerInterfaceType = InitializerType;
|
|
}
|
|
|
|
return InitializerInterfaceType;
|
|
}
|
|
|
|
void ConstructorDecl::setInitializerInterfaceType(Type t) {
|
|
assert(!t->is<PolymorphicFunctionType>()
|
|
&& "polymorphic function type is invalid interface type");
|
|
InitializerInterfaceType = t;
|
|
}
|
|
|
|
ConstructorDecl::BodyInitKind
|
|
ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
|
|
ApplyExpr **init) const {
|
|
assert(hasBody() && "Constructor does not have a definition");
|
|
|
|
if (init)
|
|
*init = nullptr;
|
|
|
|
// If we already computed the result, return it.
|
|
if (ConstructorDeclBits.ComputedBodyInitKind) {
|
|
return static_cast<BodyInitKind>(
|
|
ConstructorDeclBits.ComputedBodyInitKind - 1);
|
|
}
|
|
|
|
|
|
struct FindReferenceToInitializer : ASTWalker {
|
|
const ConstructorDecl *Decl;
|
|
BodyInitKind Kind = BodyInitKind::None;
|
|
ApplyExpr *InitExpr = nullptr;
|
|
DiagnosticEngine *Diags;
|
|
|
|
FindReferenceToInitializer(const ConstructorDecl *decl,
|
|
DiagnosticEngine *diags)
|
|
: Decl(decl), Diags(diags) { }
|
|
|
|
bool isSelfExpr(Expr *E) {
|
|
E = E->getSemanticsProvidingExpr();
|
|
|
|
if (auto ATSE = dyn_cast<ArchetypeToSuperExpr>(E))
|
|
E = ATSE->getSubExpr();
|
|
if (auto IOE = dyn_cast<InOutExpr>(E))
|
|
E = IOE->getSubExpr();
|
|
if (auto LE = dyn_cast<LoadExpr>(E))
|
|
E = LE->getSubExpr();
|
|
if (auto DRE = dyn_cast<DeclRefExpr>(E))
|
|
return DRE->getDecl() == Decl->getImplicitSelfDecl();
|
|
|
|
return false;
|
|
}
|
|
|
|
std::pair<bool, Expr*> walkToExprPre(Expr *E) override {
|
|
// Don't walk into closures.
|
|
if (isa<ClosureExpr>(E))
|
|
return { false, E };
|
|
|
|
// Look for calls of a constructor on self or super.
|
|
auto apply = dyn_cast<ApplyExpr>(E);
|
|
if (!apply)
|
|
return { true, E };
|
|
|
|
auto Callee = apply->getFn()->getSemanticsProvidingExpr();
|
|
|
|
Expr *arg;
|
|
|
|
if (isa<OtherConstructorDeclRefExpr>(Callee)) {
|
|
arg = apply->getArg();
|
|
} else if (auto *UCE = dyn_cast<UnresolvedConstructorExpr>(Callee)) {
|
|
arg = UCE->getSubExpr();
|
|
} else if (auto *CRE = dyn_cast<ConstructorRefCallExpr>(Callee)) {
|
|
arg = CRE->getArg();
|
|
} else {
|
|
// Not a constructor call.
|
|
return { true, E };
|
|
}
|
|
|
|
// Look for a base of 'self' or 'super'.
|
|
BodyInitKind myKind;
|
|
if (arg->isSuperExpr())
|
|
myKind = BodyInitKind::Chained;
|
|
else if (isSelfExpr(arg))
|
|
myKind = BodyInitKind::Delegating;
|
|
else {
|
|
// We're constructing something else.
|
|
return { true, E };
|
|
}
|
|
|
|
if (Kind == BodyInitKind::None) {
|
|
Kind = myKind;
|
|
|
|
// If we're not emitting diagnostics, we're done.
|
|
if (!Diags)
|
|
return { false, nullptr };
|
|
|
|
InitExpr = apply;
|
|
return { true, E };
|
|
}
|
|
|
|
assert(Diags && "Failed to abort traversal early");
|
|
|
|
// If the kind changed, complain.
|
|
if (Kind != myKind) {
|
|
// The kind changed. Complain.
|
|
Diags->diagnose(E->getLoc(), diag::init_delegates_and_chains);
|
|
Diags->diagnose(InitExpr->getLoc(), diag::init_delegation_or_chain,
|
|
Kind == BodyInitKind::Chained);
|
|
}
|
|
|
|
return { true, E };
|
|
}
|
|
};
|
|
|
|
FindReferenceToInitializer finder(this, diags);
|
|
getBody()->walk(finder);
|
|
|
|
// get the kind out of the finder.
|
|
auto Kind = finder.Kind;
|
|
|
|
|
|
// If we didn't find any delegating or chained initializers, check whether
|
|
// the initializer was explicitly marked 'convenience'.
|
|
if (Kind == BodyInitKind::None && getAttrs().hasAttribute<ConvenienceAttr>())
|
|
Kind = BodyInitKind::Delegating;
|
|
|
|
// If wes till don't know, check whether we have a class with a superclass: it
|
|
// gets an implicit chained initializer.
|
|
if (Kind == BodyInitKind::None) {
|
|
if (auto classDecl = getDeclContext()->getDeclaredTypeInContext()
|
|
->getClassOrBoundGenericClass()) {
|
|
if (classDecl->getSuperclass())
|
|
Kind = BodyInitKind::ImplicitChained;
|
|
}
|
|
}
|
|
|
|
// Cache the result if it is trustworthy.
|
|
if (diags) {
|
|
auto *mutableThis = const_cast<ConstructorDecl *>(this);
|
|
mutableThis->ConstructorDeclBits.ComputedBodyInitKind =
|
|
static_cast<unsigned>(Kind) + 1;
|
|
if (init)
|
|
*init = finder.InitExpr;
|
|
}
|
|
|
|
return Kind;
|
|
}
|
|
|
|
SourceRange DestructorDecl::getSourceRange() const {
|
|
if (getBodyKind() == BodyKind::Unparsed ||
|
|
getBodyKind() == BodyKind::Skipped)
|
|
return { getDestructorLoc(), BodyRange.End };
|
|
|
|
if (getBodyKind() == BodyKind::None)
|
|
return getDestructorLoc();
|
|
|
|
return { getDestructorLoc(), getBody()->getEndLoc() };
|
|
}
|
|
|
|
void InfixOperatorDecl::collectOperatorKeywordRanges(SmallVectorImpl
|
|
<CharSourceRange> &Ranges) {
|
|
auto AddToRange = [&] (SourceLoc Loc, StringRef Word) {
|
|
if (Loc.isValid())
|
|
Ranges.push_back(CharSourceRange(Loc, strlen(Word.data())));
|
|
};
|
|
AddToRange(AssociativityLoc, "associativity");
|
|
AddToRange(AssignmentLoc, "assignment");
|
|
AddToRange(PrecedenceLoc, "precedence");
|
|
}
|
|
|
|
bool FuncDecl::isDeferBody() const {
|
|
return getName() == getASTContext().getIdentifier("$defer");
|
|
}
|