mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Previously, we were creating the type corresponding to class/struct/union declarations as part of creating the declaration node, which happens at parse time. The main problem with this (at the moment) occurs with nested nominal types, where we'd end up with the wrong "parent" type when the type was nested inside an extension (because the extension hadn't been resolved at the time we accessed the parent's type). Amusingly, only code completion observed this, because the canonical type system hid the problem. The churn in the code-completion tests come from the fact that we now have the proper declared type for class/struct/union declarations within extensions. Take a step toward order-independent type checking by setting the type of a class/struct/union declaration in type checking when we either find the declaration (e.g., due to name lookup) or walk to the declaration (in our walk of the whole translation unit to type-check it), extending the existing TypeChecker::validateTypeDecl() entry point and adding a few more callers. The removeShadowedDecls() hack is awful; this needs to move out to the callers, which should be abstracted better in the type checker anyway. Incremental, non-obvious step toward fixing the representation of polymorphic function types. This yak has a *lot* of hair. Swift SVN r7444
1065 lines
34 KiB
C++
1065 lines
34 KiB
C++
//===--- Decl.cpp - Swift Language Decl ASTs ------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 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/AST.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/TypeLoc.h"
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace swift;
|
|
|
|
/// getASTContext - Return the ASTContext for a specified DeclContetx by
|
|
/// walking up to the translation unit and returning its ASTContext.
|
|
ASTContext &DeclContext::getASTContext() {
|
|
if (Module *M = dyn_cast<Module>(this))
|
|
return M->Ctx;
|
|
|
|
return getParent()->getASTContext();
|
|
}
|
|
|
|
Type DeclContext::getDeclaredTypeOfContext() const {
|
|
switch (getContextKind()) {
|
|
case DeclContextKind::BuiltinModule:
|
|
case DeclContextKind::CapturingExpr:
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
case DeclContextKind::TranslationUnit:
|
|
case DeclContextKind::SerializedModule:
|
|
case DeclContextKind::ClangModule:
|
|
case DeclContextKind::ConstructorDecl:
|
|
case DeclContextKind::DestructorDecl:
|
|
return Type();
|
|
|
|
case DeclContextKind::ExtensionDecl: {
|
|
auto type = cast<ExtensionDecl>(this)->getExtendedType();
|
|
return type->getNominalOrBoundGenericNominal()->getDeclaredType();
|
|
}
|
|
|
|
case DeclContextKind::NominalTypeDecl:
|
|
return cast<NominalTypeDecl>(this)->getDeclaredType();
|
|
}
|
|
}
|
|
|
|
Type DeclContext::getDeclaredTypeInContext() {
|
|
switch (getContextKind()) {
|
|
case DeclContextKind::BuiltinModule:
|
|
case DeclContextKind::CapturingExpr:
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
case DeclContextKind::TranslationUnit:
|
|
case DeclContextKind::SerializedModule:
|
|
case DeclContextKind::ClangModule:
|
|
case DeclContextKind::ConstructorDecl:
|
|
case DeclContextKind::DestructorDecl:
|
|
return Type();
|
|
|
|
case DeclContextKind::ExtensionDecl:
|
|
return cast<ExtensionDecl>(this)->getExtendedType();
|
|
case DeclContextKind::NominalTypeDecl:
|
|
return cast<NominalTypeDecl>(this)->getDeclaredTypeInContext();
|
|
}
|
|
|
|
}
|
|
|
|
GenericParamList *DeclContext::getGenericParamsOfContext() const {
|
|
switch (getContextKind()) {
|
|
case DeclContextKind::BuiltinModule:
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
case DeclContextKind::TranslationUnit:
|
|
case DeclContextKind::SerializedModule:
|
|
case DeclContextKind::ClangModule:
|
|
return nullptr;
|
|
|
|
case DeclContextKind::CapturingExpr: {
|
|
if (auto funcE = dyn_cast<FuncExpr>(this)) {
|
|
if (auto funcD = funcE->getDecl()) {
|
|
if (auto gp = funcD->getGenericParams()) {
|
|
return gp;
|
|
}
|
|
|
|
return funcD->getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
case DeclContextKind::ConstructorDecl: {
|
|
auto constructor = cast<ConstructorDecl>(this);
|
|
if (auto gp = constructor->getGenericParams())
|
|
return gp;
|
|
|
|
return constructor->getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
|
|
case DeclContextKind::DestructorDecl:
|
|
return cast<DestructorDecl>(this)->getDeclContext()
|
|
->getGenericParamsOfContext();
|
|
|
|
case DeclContextKind::NominalTypeDecl: {
|
|
auto nominal = cast<NominalTypeDecl>(this);
|
|
if (auto gp = nominal->getGenericParams())
|
|
return gp;
|
|
|
|
return nominal->getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
|
|
case DeclContextKind::ExtensionDecl: {
|
|
auto extension = cast<ExtensionDecl>(this);
|
|
auto extendedType = extension->getExtendedType();
|
|
if (auto bound = extendedType->getAs<BoundGenericType>()) {
|
|
return bound->getDecl()->getGenericParams();
|
|
}
|
|
if (auto nominalTy = extendedType->getAs<NominalType>()) {
|
|
auto nominalDecl = nominalTy->getDecl();
|
|
return nominalDecl->getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
llvm_unreachable("Unhandled declaration context kind");
|
|
}
|
|
|
|
Module *DeclContext::getParentModule() const {
|
|
const DeclContext *DC = this;
|
|
while (!DC->isModuleContext())
|
|
DC = DC->getParent();
|
|
return const_cast<Module *>(cast<Module>(DC));
|
|
}
|
|
|
|
// Only allow allocation of Decls using the allocator in ASTContext.
|
|
void *Decl::operator new(size_t Bytes, ASTContext &C,
|
|
unsigned Alignment) {
|
|
return C.Allocate(Bytes, Alignment);
|
|
}
|
|
|
|
// Only allow allocation of DeclContext using the allocator in ASTContext.
|
|
void *DeclContext::operator new(size_t Bytes, 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, ASTContext &C,
|
|
unsigned Alignment) {
|
|
return C.Allocate(Bytes, Alignment);
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
ClangNode Decl::getClangNodeSlow() {
|
|
return getASTContext().getClangNode(this);
|
|
}
|
|
|
|
void Decl::setClangNode(ClangNode node) {
|
|
DeclBits.FromClang = true;
|
|
getASTContext().setClangNode(this, node);
|
|
}
|
|
|
|
GenericParamList::GenericParamList(SourceLoc LAngleLoc,
|
|
ArrayRef<GenericParam> Params,
|
|
SourceLoc WhereLoc,
|
|
MutableArrayRef<Requirement> Requirements,
|
|
SourceLoc RAngleLoc)
|
|
: Brackets(LAngleLoc, RAngleLoc), NumParams(Params.size()),
|
|
WhereLoc(WhereLoc), Requirements(Requirements),
|
|
OuterParameters(nullptr)
|
|
{
|
|
memcpy(this + 1, Params.data(), NumParams * sizeof(GenericParam));
|
|
}
|
|
|
|
GenericParamList *GenericParamList::create(ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericParam> Params,
|
|
SourceLoc RAngleLoc) {
|
|
unsigned Size = sizeof(GenericParamList)
|
|
+ sizeof(GenericParam) * Params.size();
|
|
void *Mem = Context.Allocate(Size, alignof(GenericParamList));
|
|
return new (Mem) GenericParamList(LAngleLoc, Params, SourceLoc(),
|
|
MutableArrayRef<Requirement>(),
|
|
RAngleLoc);
|
|
}
|
|
|
|
GenericParamList *
|
|
GenericParamList::create(const ASTContext &Context,
|
|
SourceLoc LAngleLoc,
|
|
ArrayRef<GenericParam> Params,
|
|
SourceLoc WhereLoc,
|
|
MutableArrayRef<Requirement> Requirements,
|
|
SourceLoc RAngleLoc) {
|
|
unsigned Size = sizeof(GenericParamList)
|
|
+ sizeof(GenericParam) * Params.size();
|
|
void *Mem = Context.Allocate(Size, alignof(GenericParamList));
|
|
return new (Mem) GenericParamList(LAngleLoc, Params,
|
|
WhereLoc,
|
|
Context.AllocateCopy(Requirements),
|
|
RAngleLoc);
|
|
}
|
|
|
|
ImportDecl *ImportDecl::create(ASTContext &Ctx, DeclContext *DC,
|
|
SourceLoc ImportLoc, ImportKind Kind,
|
|
SourceLoc KindLoc, bool Exported,
|
|
ArrayRef<AccessPathElement> Path) {
|
|
assert(!Path.empty());
|
|
assert(Kind == ImportKind::Module || Path.size() > 1);
|
|
void *buffer = Ctx.Allocate(sizeof(ImportDecl) +
|
|
Path.size() * sizeof(AccessPathElement),
|
|
alignof(ImportDecl));
|
|
return new (buffer) ImportDecl(DC, ImportLoc, Kind, KindLoc, Exported, Path);
|
|
}
|
|
|
|
ImportDecl::ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K,
|
|
SourceLoc KindLoc, bool Exported,
|
|
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");
|
|
ImportDeclBits.IsExported = Exported;
|
|
std::uninitialized_copy(Path.begin(), Path.end(), getPathBuffer());
|
|
}
|
|
|
|
SourceRange PatternBindingDecl::getSourceRange() const {
|
|
if (Init && !Init->isImplicit())
|
|
return { VarLoc, Init->getSourceRange().End };
|
|
return { VarLoc, Pat->getSourceRange().End };
|
|
}
|
|
|
|
SourceLoc TopLevelCodeDecl::getStartLoc() const {
|
|
return Body->getStartLoc();
|
|
}
|
|
|
|
SourceRange TopLevelCodeDecl::getSourceRange() const {
|
|
return Body->getSourceRange();
|
|
}
|
|
|
|
bool ValueDecl::isSettableOnBase(Type baseType) const {
|
|
if (!isSettable()) return false;
|
|
if (!baseType) return true;
|
|
return (baseType->isSettableLValue() ||
|
|
baseType->getRValueType()->hasReferenceSemantics());
|
|
}
|
|
|
|
static Type getRValueType(Type type) {
|
|
CanType canType = type->getCanonicalType();
|
|
|
|
// Strip l-valueness.
|
|
if (isa<LValueType>(canType)) {
|
|
return type->castTo<LValueType>()->getObjectType();
|
|
|
|
// Ignore ownership qualification.
|
|
} else if (isa<ReferenceStorageType>(canType)) {
|
|
return type->castTo<ReferenceStorageType>()->getReferentType();
|
|
|
|
// No other transforms necessary.
|
|
} else {
|
|
return type;
|
|
}
|
|
}
|
|
|
|
/// getTypeOfRValue - Return the type of an r-value reference to this value.
|
|
Type ValueDecl::getTypeOfRValue() const {
|
|
Type type = getType();
|
|
if (isReferencedAsLValue()) {
|
|
type = getRValueType(type);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
/// isDefinition - Return true if this is a definition of a decl, not a
|
|
/// forward declaration (e.g. of a function) that is implemented outside of
|
|
/// the swift code.
|
|
bool ValueDecl::isDefinition() const {
|
|
switch (getKind()) {
|
|
case DeclKind::Import:
|
|
case DeclKind::Extension:
|
|
case DeclKind::PatternBinding:
|
|
case DeclKind::Subscript:
|
|
case DeclKind::TopLevelCode:
|
|
case DeclKind::Constructor:
|
|
case DeclKind::Destructor:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
llvm_unreachable("non-value decls shouldn't get here");
|
|
|
|
case DeclKind::Func:
|
|
return cast<FuncDecl>(this)->getBody() != 0;
|
|
|
|
case DeclKind::Var:
|
|
case DeclKind::Union:
|
|
case DeclKind::UnionElement:
|
|
case DeclKind::Struct:
|
|
case DeclKind::Class:
|
|
case DeclKind::TypeAlias:
|
|
case DeclKind::GenericTypeParam:
|
|
case DeclKind::AssociatedType:
|
|
case DeclKind::Protocol:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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::TopLevelCode:
|
|
case DeclKind::InfixOperator:
|
|
case DeclKind::PrefixOperator:
|
|
case DeclKind::PostfixOperator:
|
|
llvm_unreachable("Not a ValueDecl");
|
|
|
|
case DeclKind::Class:
|
|
case DeclKind::Union:
|
|
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::UnionElement:
|
|
// union elements are not instance members.
|
|
return false;
|
|
|
|
case DeclKind::Subscript:
|
|
// Subscripts are always instance members.
|
|
return true;
|
|
|
|
case DeclKind::Var:
|
|
// Variables are always instance variables.
|
|
// FIXME: Until we get static variables.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
std::pair<DefaultArgumentKind, Type>
|
|
ValueDecl::getDefaultArg(unsigned index) const {
|
|
ArrayRef<const Pattern *> patterns;
|
|
if (auto func = dyn_cast<FuncDecl>(this)) {
|
|
patterns = func->getBody()->getArgParamPatterns();
|
|
|
|
// Skip the 'this' parameter; it is not counted.
|
|
if (func->getDeclContext()->isTypeContext())
|
|
patterns = patterns.slice(1);
|
|
} else {
|
|
auto constructor = dyn_cast<ConstructorDecl>(this);
|
|
patterns = constructor->getArguments();
|
|
}
|
|
|
|
// Find the (sub-)pattern for this index.
|
|
// FIXME: This is O(n), which is lame. We should fix the FuncDecl
|
|
// representation.
|
|
const TuplePatternElt *found = nullptr;
|
|
for (auto origPattern : patterns) {
|
|
auto pattern = origPattern->getSemanticsProvidingPattern();
|
|
auto tuplePattern = dyn_cast<TuplePattern>(pattern);
|
|
if (!tuplePattern) {
|
|
if (index == 0) {
|
|
return { DefaultArgumentKind::None, Type() };
|
|
}
|
|
|
|
--index;
|
|
continue;
|
|
}
|
|
|
|
|
|
for (auto &elt : tuplePattern->getFields()) {
|
|
if (index == 0) {
|
|
found = &elt;
|
|
break;
|
|
}
|
|
--index;
|
|
}
|
|
|
|
if (found)
|
|
break;
|
|
}
|
|
|
|
assert(found && "No argument with this index");
|
|
return { found->getDefaultArgKind(), found->getPattern()->getType() };
|
|
}
|
|
|
|
Type TypeDecl::getDeclaredType() const {
|
|
if (auto TAD = dyn_cast<TypeAliasDecl>(this))
|
|
return TAD->getAliasType();
|
|
if (auto typeParam = dyn_cast<AbstractTypeParamDecl>(this))
|
|
return typeParam->getType()->castTo<MetaTypeType>()->getInstanceType();
|
|
return cast<NominalTypeDecl>(this)->getDeclaredType();
|
|
}
|
|
|
|
Type NominalTypeDecl::getDeclaredTypeInContext() {
|
|
if (DeclaredTyInContext)
|
|
return DeclaredTyInContext;
|
|
|
|
Type Ty = getDeclaredType();
|
|
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())
|
|
GenericArgs.push_back(Param.getAsTypeParam()->getDeclaredType());
|
|
Ty = BoundGenericType::get(D, getDeclContext()->getDeclaredTypeInContext(),
|
|
GenericArgs);
|
|
}
|
|
DeclaredTyInContext = Ty;
|
|
return DeclaredTyInContext;
|
|
}
|
|
|
|
ExtensionRange NominalTypeDecl::getExtensions() {
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
TypeAliasDecl::TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
|
|
SourceLoc NameLoc, TypeLoc UnderlyingTy,
|
|
DeclContext *DC,
|
|
MutableArrayRef<TypeLoc> Inherited)
|
|
: TypeDecl(DeclKind::TypeAlias, DC, Name, Inherited, Type()),
|
|
TypeAliasLoc(TypeAliasLoc), NameLoc(NameLoc),
|
|
UnderlyingTy(UnderlyingTy)
|
|
{
|
|
// Set the type of the TypeAlias to the right MetaTypeType.
|
|
ASTContext &Ctx = getASTContext();
|
|
AliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
|
|
setType(MetaTypeType::get(AliasTy, Ctx));
|
|
}
|
|
|
|
SourceRange TypeAliasDecl::getSourceRange() const {
|
|
if (UnderlyingTy.hasLocation())
|
|
return { TypeAliasLoc, UnderlyingTy.getSourceRange().End };
|
|
// FIXME: Inherits clauses
|
|
return { TypeAliasLoc, NameLoc };
|
|
}
|
|
|
|
GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name,
|
|
SourceLoc nameLoc,
|
|
unsigned depth, unsigned index)
|
|
: AbstractTypeParamDecl(DeclKind::GenericTypeParam, dc, name),
|
|
NameLoc(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 = NameLoc;
|
|
|
|
if (!getInherited().empty()) {
|
|
endLoc = getInherited().back().getSourceRange().End;
|
|
}
|
|
return SourceRange(NameLoc, endLoc);
|
|
}
|
|
|
|
AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc,
|
|
Identifier name, SourceLoc nameLoc)
|
|
: AbstractTypeParamDecl(DeclKind::AssociatedType, dc, name),
|
|
KeywordLoc(keywordLoc), NameLoc(nameLoc)
|
|
{
|
|
auto &ctx = dc->getASTContext();
|
|
auto type = new (ctx, AllocationArena::Permanent) AssociatedTypeType(this);
|
|
setType(MetaTypeType::get(type, ctx));
|
|
}
|
|
|
|
SourceRange AssociatedTypeDecl::getSourceRange() const {
|
|
SourceLoc endLoc = NameLoc;
|
|
|
|
if (!getInherited().empty()) {
|
|
endLoc = getInherited().back().getSourceRange().End;
|
|
}
|
|
return SourceRange(KeywordLoc, endLoc);
|
|
}
|
|
|
|
UnionDecl::UnionDecl(SourceLoc UnionLoc, bool Enum,
|
|
Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Union, Parent, Name, Inherited, GenericParams),
|
|
UnionLoc(UnionLoc), NameLoc(NameLoc) { }
|
|
|
|
StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Struct, Parent, Name, Inherited, GenericParams),
|
|
StructLoc(StructLoc), NameLoc(NameLoc) { }
|
|
|
|
ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
|
|
MutableArrayRef<TypeLoc> Inherited,
|
|
GenericParamList *GenericParams, DeclContext *Parent)
|
|
: NominalTypeDecl(DeclKind::Class, Parent, Name, Inherited, GenericParams),
|
|
ClassLoc(ClassLoc), NameLoc(NameLoc) {
|
|
ClassDeclBits.Circularity
|
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
|
}
|
|
|
|
UnionElementDecl *UnionDecl::getElement(Identifier Name) const {
|
|
// FIXME: Linear search is not great for large union decls.
|
|
for (Decl *D : getMembers())
|
|
if (UnionElementDecl *Elt = dyn_cast<UnionElementDecl>(D))
|
|
if (Elt->getName() == Name)
|
|
return Elt;
|
|
return 0;
|
|
}
|
|
|
|
ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
|
|
SourceLoc NameLoc, Identifier Name,
|
|
MutableArrayRef<TypeLoc> Inherited)
|
|
: NominalTypeDecl(DeclKind::Protocol, DC, Name, Inherited, nullptr),
|
|
ProtocolLoc(ProtocolLoc), NameLoc(NameLoc)
|
|
{
|
|
// Compute the associated type for this ClassDecl.
|
|
ASTContext &Ctx = DC->getASTContext();
|
|
DeclaredTy = new (Ctx, AllocationArena::Permanent) ProtocolType(this, Ctx);
|
|
// Set the type of the ProtocolDecl to the right MetaTypeType.
|
|
setType(MetaTypeType::get(DeclaredTy, Ctx));
|
|
|
|
ProtocolDeclBits.RequiresClassValid = false;
|
|
ProtocolDeclBits.RequiresClass = false;
|
|
ProtocolDeclBits.ExistentialConformsToSelfValid = false;
|
|
ProtocolDeclBits.ExistentialConformsToSelf = false;
|
|
ProtocolDeclBits.KnownProtocol = 0;
|
|
ProtocolDeclBits.Circularity
|
|
= static_cast<unsigned>(CircularityCheck::Unchecked);
|
|
}
|
|
|
|
bool ProtocolDecl::inheritsFrom(const ProtocolDecl *Super) const {
|
|
if (this == Super)
|
|
return false;
|
|
|
|
llvm::SmallPtrSet<const ProtocolDecl *, 4> Visited;
|
|
SmallVector<const ProtocolDecl *, 4> Stack;
|
|
|
|
Stack.push_back(this);
|
|
Visited.insert(this);
|
|
while (!Stack.empty()) {
|
|
const ProtocolDecl *Current = Stack.back();
|
|
Stack.pop_back();
|
|
|
|
for (auto InheritedProto : Current->getProtocols()) {
|
|
if (InheritedProto == Super)
|
|
return true;
|
|
|
|
if (Visited.insert(InheritedProto))
|
|
Stack.push_back(InheritedProto);
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ProtocolDecl::collectInherited(
|
|
llvm::SmallPtrSet<ProtocolDecl *, 4> &Inherited) {
|
|
SmallVector<const ProtocolDecl *, 4> Stack;
|
|
|
|
Stack.push_back(this);
|
|
while (!Stack.empty()) {
|
|
const ProtocolDecl *Current = Stack.back();
|
|
Stack.pop_back();
|
|
|
|
for (auto InheritedProto : Current->getProtocols()) {
|
|
if (Inherited.insert(InheritedProto))
|
|
Stack.push_back(InheritedProto);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ProtocolDecl::requiresClassSlow() {
|
|
ProtocolDeclBits.RequiresClass = false;
|
|
ProtocolDeclBits.RequiresClassValid = true;
|
|
|
|
if (getAttrs().isClassProtocol()) {
|
|
ProtocolDeclBits.RequiresClass = true;
|
|
return true;
|
|
}
|
|
|
|
// Check inherited protocols for class-ness.
|
|
for (auto *proto : getProtocols()) {
|
|
if (proto->requiresClass()) {
|
|
ProtocolDeclBits.RequiresClass = true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
AssociatedTypeDecl *ProtocolDecl::getThis() const {
|
|
for (auto member : getMembers()) {
|
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(member))
|
|
if (assocType->isThis())
|
|
return assocType;
|
|
}
|
|
llvm_unreachable("No 'This' associated type?");
|
|
}
|
|
|
|
void VarDecl::setProperty(ASTContext &Context, SourceLoc LBraceLoc,
|
|
FuncDecl *Get, FuncDecl *Set, SourceLoc RBraceLoc) {
|
|
assert(!GetSet && "Variable is already a property?");
|
|
void *Mem = Context.Allocate(sizeof(GetSetRecord), alignof(GetSetRecord));
|
|
GetSet = new (Mem) GetSetRecord;
|
|
GetSet->Braces = SourceRange(LBraceLoc, RBraceLoc);
|
|
GetSet->Get = Get;
|
|
GetSet->Set = Set;
|
|
|
|
if (Get)
|
|
Get->makeGetter(this);
|
|
if (Set)
|
|
Set->makeSetter(this);
|
|
}
|
|
|
|
bool VarDecl::isAnonClosureParam() const {
|
|
auto name = getName();
|
|
if (name.empty())
|
|
return false;
|
|
|
|
auto nameStr = name.str();
|
|
if (nameStr.empty())
|
|
return false;
|
|
|
|
return nameStr[0] == '$';
|
|
}
|
|
|
|
VarDecl *FuncDecl::getImplicitThisDecl() const {
|
|
return Body->getImplicitThisDecl();
|
|
}
|
|
|
|
/// getNaturalArgumentCount - Returns the "natural" number of
|
|
/// argument clauses taken by this function.
|
|
unsigned FuncDecl::getNaturalArgumentCount() const {
|
|
return getBody()->getNaturalArgumentCount();
|
|
}
|
|
|
|
ArrayRef<ValueDecl*> FuncDecl::getCaptures() const {
|
|
if (Body)
|
|
return Body->getCaptures();
|
|
else
|
|
return {};
|
|
}
|
|
|
|
/// getExtensionType - If this is a method in a type extension for some type,
|
|
/// return that type, otherwise return Type().
|
|
Type FuncDecl::getExtensionType() const {
|
|
DeclContext *DC = getDeclContext();
|
|
switch (DC->getContextKind()) {
|
|
case DeclContextKind::TranslationUnit:
|
|
case DeclContextKind::BuiltinModule:
|
|
case DeclContextKind::SerializedModule:
|
|
case DeclContextKind::ClangModule:
|
|
case DeclContextKind::CapturingExpr:
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
case DeclContextKind::ConstructorDecl:
|
|
case DeclContextKind::DestructorDecl:
|
|
return Type();
|
|
|
|
case DeclContextKind::NominalTypeDecl:
|
|
return cast<NominalTypeDecl>(DC)->getDeclaredType();
|
|
case DeclContextKind::ExtensionDecl: {
|
|
auto ext = cast<ExtensionDecl>(DC);
|
|
if (ext->isInvalid())
|
|
return ErrorType::get(getASTContext());
|
|
return ext->getExtendedType();
|
|
}
|
|
}
|
|
llvm_unreachable("bad context kind");
|
|
}
|
|
|
|
|
|
/// computeThisType - If this is a method in a type extension for some type,
|
|
/// compute and return the type to be used for the 'this' argument of the
|
|
/// type (which varies based on whether the extended type is a reference type
|
|
/// or not), or an empty Type() if no 'this' argument should exist. This can
|
|
/// only be used after name binding has resolved types.
|
|
Type FuncDecl::computeThisType(GenericParamList **OuterGenericParams) const {
|
|
if (OuterGenericParams)
|
|
*OuterGenericParams = nullptr;
|
|
|
|
Type ContainerType = getExtensionType();
|
|
if (ContainerType.isNull()) return ContainerType;
|
|
|
|
// For a protocol, the type of 'this' is the associated type 'This', not
|
|
// the protocol itself.
|
|
if (auto Protocol = ContainerType->getAs<ProtocolType>()) {
|
|
AssociatedTypeDecl *This = 0;
|
|
for (auto Member : Protocol->getDecl()->getMembers()) {
|
|
This = dyn_cast<AssociatedTypeDecl>(Member);
|
|
if (!This)
|
|
continue;
|
|
|
|
if (This->isThis())
|
|
break;
|
|
|
|
This = nullptr;
|
|
}
|
|
|
|
assert(This && "Missing 'This' associated type in protocol");
|
|
ContainerType = This->getDeclaredType();
|
|
}
|
|
|
|
if (UnboundGenericType *UGT = ContainerType->getAs<UnboundGenericType>()) {
|
|
// If we have an unbound generic type, bind the type to the archetypes
|
|
// in the type's definition.
|
|
NominalTypeDecl *D = UGT->getDecl();
|
|
ContainerType = getDeclContext()->getDeclaredTypeInContext();
|
|
|
|
if (OuterGenericParams)
|
|
*OuterGenericParams = D->getGenericParams();
|
|
} else if (OuterGenericParams) {
|
|
*OuterGenericParams = getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
|
|
// 'static' functions have 'this' of type metatype<T>.
|
|
if (isStatic())
|
|
return MetaTypeType::get(ContainerType, getASTContext());
|
|
|
|
if (ContainerType->hasReferenceSemantics())
|
|
return ContainerType;
|
|
|
|
// Otherwise, make an l-value type.
|
|
return LValueType::get(ContainerType,
|
|
LValueType::Qual::DefaultForByrefThis,
|
|
getASTContext());
|
|
}
|
|
|
|
bool FuncDecl::isUnaryOperator() const {
|
|
if (!isOperator())
|
|
return false;
|
|
|
|
unsigned opArgIndex = isa<ProtocolDecl>(getDeclContext()) ? 1 : 0;
|
|
|
|
auto *argTuple
|
|
= dyn_cast<TuplePattern>(getBody()->getArgParamPatterns()[opArgIndex]);
|
|
if (!argTuple)
|
|
return true;
|
|
|
|
return argTuple->getNumFields() == 1 && !argTuple->hasVararg();
|
|
}
|
|
|
|
bool FuncDecl::isBinaryOperator() const {
|
|
if (!isOperator())
|
|
return false;
|
|
|
|
unsigned opArgIndex = isa<ProtocolDecl>(getDeclContext()) ? 1 : 0;
|
|
|
|
auto *argTuple
|
|
= dyn_cast<TuplePattern>(getBody()->getArgParamPatterns()[opArgIndex]);
|
|
if (!argTuple)
|
|
return false;
|
|
|
|
return argTuple->getNumFields() == 2
|
|
|| (argTuple->getNumFields() == 1 && argTuple->hasVararg());
|
|
}
|
|
|
|
StringRef VarDecl::getObjCGetterSelector(SmallVectorImpl<char> &buffer) const {
|
|
llvm::raw_svector_ostream out(buffer);
|
|
|
|
// The getter selector is the property name itself.
|
|
// FIXME: 'is' prefix for boolean properties?
|
|
out << getName().str();
|
|
return out.str();
|
|
}
|
|
|
|
StringRef VarDecl::getObjCSetterSelector(SmallVectorImpl<char> &buffer) const {
|
|
llvm::raw_svector_ostream out(buffer);
|
|
|
|
// The setter selector for, e.g., 'fooBar' is 'setFooBar:', with the
|
|
// property name capitalized and preceded by 'set'.
|
|
StringRef name = getName().str();
|
|
assert(name.size() >= 1 && "empty var name?!");
|
|
|
|
out << "set" << char(toupper(name[0])) << name.slice(1, name.size()) << ':';
|
|
return out.str();
|
|
}
|
|
|
|
/// Produce the selector for this "Objective-C method" in the given buffer.
|
|
StringRef FuncDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
|
|
assert(buffer.empty());
|
|
|
|
// Property accessors should go through a different path.
|
|
assert(!isGetterOrSetter());
|
|
|
|
llvm::raw_svector_ostream out(buffer);
|
|
|
|
// Start with the method name.
|
|
out << getName().str();
|
|
|
|
// We should always have exactly two levels of argument pattern.
|
|
auto argPatterns = getBody()->getArgParamPatterns();
|
|
assert(argPatterns.size() == 2);
|
|
const Pattern *pattern = argPatterns[1];
|
|
auto tuple = dyn_cast<TuplePattern>(pattern);
|
|
|
|
// If it's an empty tuple pattern, it's a nullary selector.
|
|
if (tuple && tuple->getNumFields() == 0)
|
|
return StringRef(buffer.data(), buffer.size());
|
|
|
|
// Otherwise, it's at least a unary selector.
|
|
out << ':';
|
|
|
|
// If it's a unary selector, we're done.
|
|
if (!tuple) {
|
|
return out.str();
|
|
}
|
|
|
|
// For every element except the first, add a selector component.
|
|
for (auto &elt : tuple->getFields().slice(1)) {
|
|
auto eltPattern = elt.getPattern()->getSemanticsProvidingPattern();
|
|
|
|
// Add a label to the selector component if there's a tag.
|
|
if (auto named = dyn_cast<NamedPattern>(eltPattern)) {
|
|
out << named->getBoundName().str();
|
|
}
|
|
|
|
// Add the colon regardless. Yes, this can sometimes create a
|
|
// component that's just a colon, and that's actually a legal
|
|
// selector.
|
|
out << ':';
|
|
}
|
|
|
|
return out.str();
|
|
}
|
|
|
|
SourceRange FuncDecl::getSourceRange() const {
|
|
return Body->getSourceRange();
|
|
}
|
|
|
|
SourceRange UnionElementDecl::getSourceRange() const {
|
|
if (ResultType.hasLocation())
|
|
return {getStartLoc(), ResultType.getSourceRange().End};
|
|
if (ArgumentType.hasLocation())
|
|
return {getStartLoc(), ArgumentType.getSourceRange().End};
|
|
return {getStartLoc(), IdentifierLoc};
|
|
}
|
|
|
|
SourceLoc SubscriptDecl::getLoc() const {
|
|
return Indices->getStartLoc();
|
|
}
|
|
|
|
SourceRange SubscriptDecl::getSourceRange() const {
|
|
if (Braces.isValid())
|
|
return { SubscriptLoc, Braces.End };
|
|
return { SubscriptLoc, ElementTy.getSourceRange().End };
|
|
}
|
|
|
|
SourceLoc ConstructorDecl::getLoc() const {
|
|
return Arguments->getStartLoc();
|
|
}
|
|
|
|
SourceRange ConstructorDecl::getSourceRange() const {
|
|
if (!Body || !Body->getEndLoc().isValid()) {
|
|
const DeclContext *DC = getDeclContext();
|
|
switch (DC->getContextKind()) {
|
|
case DeclContextKind::ExtensionDecl:
|
|
return cast<ExtensionDecl>(DC)->getLoc();
|
|
case DeclContextKind::NominalTypeDecl:
|
|
return cast<NominalTypeDecl>(DC)->getLoc();
|
|
default:
|
|
llvm_unreachable("Unhandled decl kind");
|
|
}
|
|
}
|
|
return { ConstructorLoc, Body->getEndLoc() };
|
|
}
|
|
|
|
Type
|
|
ConstructorDecl::computeThisType(GenericParamList **OuterGenericParams) const {
|
|
Type ContainerType = getDeclContext()->getDeclaredTypeOfContext();
|
|
|
|
if (UnboundGenericType *UGT = ContainerType->getAs<UnboundGenericType>()) {
|
|
// If we have an unbound generic type, bind the type to the archetypes
|
|
// in the type's definition.
|
|
NominalTypeDecl *D = UGT->getDecl();
|
|
ContainerType = getDeclContext()->getDeclaredTypeInContext();
|
|
|
|
if (OuterGenericParams)
|
|
*OuterGenericParams = D->getGenericParams();
|
|
} else if (OuterGenericParams) {
|
|
*OuterGenericParams = getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
|
|
return ContainerType;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/// Produce the selector for this "Objective-C method" in the given buffer.
|
|
StringRef
|
|
ConstructorDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
|
|
assert(buffer.empty());
|
|
|
|
llvm::raw_svector_ostream out(buffer);
|
|
|
|
|
|
// If it's an empty tuple pattern, it's the nullary selector "init".
|
|
// FIXME: This leaves us without a way to describe "new".
|
|
auto tuple = dyn_cast<TuplePattern>(Arguments);
|
|
if (tuple && tuple->getNumFields() == 0) {
|
|
out << "init";
|
|
out.flush();
|
|
return StringRef(buffer.data(), buffer.size());
|
|
}
|
|
|
|
// If it's not a tuple at all, it's the unary selector "init:".
|
|
// FIXME: Diagnose this?
|
|
if (!tuple) {
|
|
out << "init:";
|
|
out.flush();
|
|
return StringRef(buffer.data(), buffer.size());
|
|
}
|
|
|
|
// For every element, add a selector component.
|
|
for (auto &elt : tuple->getFields()) {
|
|
auto eltPattern = elt.getPattern()->getSemanticsProvidingPattern();
|
|
|
|
// Add a label to the selector component if there's a tag.
|
|
if (auto named = dyn_cast<NamedPattern>(eltPattern)) {
|
|
out << named->getBoundName().str();
|
|
}
|
|
|
|
// Add the colon regardless. Yes, this can sometimes create a
|
|
// component that's just a colon, and that's actually a legal
|
|
// selector.
|
|
out << ':';
|
|
}
|
|
|
|
return StringRef(buffer.data(), buffer.size());
|
|
}
|
|
|
|
Type
|
|
DestructorDecl::computeThisType(GenericParamList **OuterGenericParams) const {
|
|
Type ContainerType = getDeclContext()->getDeclaredTypeOfContext();
|
|
|
|
if (UnboundGenericType *UGT = ContainerType->getAs<UnboundGenericType>()) {
|
|
// If we have an unbound generic type, bind the type to the archetypes
|
|
// in the type's definition.
|
|
NominalTypeDecl *D = UGT->getDecl();
|
|
ContainerType = getDeclContext()->getDeclaredTypeInContext();
|
|
|
|
if (OuterGenericParams)
|
|
*OuterGenericParams = D->getGenericParams();
|
|
} else if (OuterGenericParams) {
|
|
*OuterGenericParams = getDeclContext()->getGenericParamsOfContext();
|
|
}
|
|
|
|
return ContainerType;
|
|
}
|
|
|
|
SourceRange DestructorDecl::getSourceRange() const {
|
|
return { DestructorLoc, Body->getEndLoc() };
|
|
}
|