mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
struct/oneof/class extension, making them instance methods. Normal variables are still not allowed in these contexts, however. The fact that we set DeclContexts late causes some consternation here, because it's not clear just how far we need to recurse in DeclContext. I've done enough to make properties work, but I'm still rather uneasy about the current state of affairs. Swift SVN r1423
563 lines
18 KiB
C++
563 lines
18 KiB
C++
//===--- Decl.h - Swift Language Declaration ASTs ---------------*- C++ -*-===//
|
|
//
|
|
// 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 defines the Decl class and subclasses.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_DECL_H
|
|
#define SWIFT_DECL_H
|
|
|
|
#include "swift/AST/DeclContext.h"
|
|
#include "swift/AST/Identifier.h"
|
|
#include "swift/AST/Type.h"
|
|
#include "swift/Basic/SourceLoc.h"
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include <cstddef>
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
class Type;
|
|
class Expr;
|
|
class FuncDecl;
|
|
class FuncExpr;
|
|
class BraceStmt;
|
|
class Component;
|
|
class DeclAttributes;
|
|
class OneOfElementDecl;
|
|
class NameAliasType;
|
|
class Pattern;
|
|
enum class Resilience : unsigned char;
|
|
class TypeAliasDecl;
|
|
|
|
enum class DeclKind {
|
|
#define DECL(Id, Parent) Id,
|
|
#define DECL_RANGE(Id, FirstId, LastId) \
|
|
First_##Id##Decl = FirstId, Last_##Id##Decl = LastId,
|
|
#include "swift/AST/DeclNodes.def"
|
|
};
|
|
|
|
/// Decl - Base class for all declarations in Swift.
|
|
class Decl {
|
|
class DeclBitfields {
|
|
friend class Decl;
|
|
unsigned Kind : 8;
|
|
};
|
|
enum { NumDeclBits = 8 };
|
|
static_assert(NumDeclBits <= 32, "fits in an unsigned");
|
|
|
|
enum { NumNamedDeclBits = NumDeclBits };
|
|
static_assert(NumNamedDeclBits <= 32, "fits in an unsigned");
|
|
|
|
class ValueDeclBitfields {
|
|
friend class ValueDecl;
|
|
unsigned : NumNamedDeclBits;
|
|
|
|
unsigned IsModuleScope : 1;
|
|
|
|
// The following flags are not necessarily meaningful for all
|
|
// kinds of value-declarations.
|
|
|
|
// NeverUsedAsLValue - Whether this decl is ever used as an lvalue
|
|
// (i.e. used in a context where it could be modified).
|
|
unsigned NeverUsedAsLValue : 1;
|
|
|
|
// HasFixedLifetime - Whether the lifetime of this decl matches its
|
|
// scope (i.e. the decl isn't captured, so it can be allocated as part of
|
|
// the stack frame.)
|
|
unsigned HasFixedLifetime : 1;
|
|
};
|
|
enum { NumValueDeclBits = NumNamedDeclBits + 3 };
|
|
static_assert(NumValueDeclBits <= 32, "fits in an unsigned");
|
|
|
|
protected:
|
|
union {
|
|
DeclBitfields DeclBits;
|
|
ValueDeclBitfields ValueDeclBits;
|
|
};
|
|
|
|
private:
|
|
DeclContext *Context;
|
|
|
|
Decl(const Decl&) = delete;
|
|
void operator=(const Decl&) = delete;
|
|
|
|
protected:
|
|
Decl(DeclKind kind, DeclContext *DC) : Context(DC) {
|
|
DeclBits.Kind = unsigned(kind);
|
|
}
|
|
|
|
public:
|
|
/// Alignment - The required alignment of Decl objects.
|
|
enum { Alignment = 8 };
|
|
|
|
DeclKind getKind() const { return DeclKind(DeclBits.Kind); }
|
|
|
|
DeclContext *getDeclContext() const { return Context; }
|
|
void setDeclContext(DeclContext *DC);
|
|
|
|
/// getASTContext - Return the ASTContext that this decl lives in.
|
|
ASTContext &getASTContext() const {
|
|
assert(Context && "Decl doesn't have an assigned context");
|
|
return Context->getASTContext();
|
|
}
|
|
|
|
SourceLoc getLocStart() const;
|
|
|
|
void dump() const;
|
|
void print(raw_ostream &OS, unsigned Indent = 0) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *) { return true; }
|
|
|
|
// Make vanilla new/delete illegal for Decls.
|
|
void *operator new(size_t Bytes) = delete;
|
|
void operator delete(void *Data) = delete;
|
|
|
|
// Only allow allocation of Decls using the allocator in ASTContext
|
|
// or by doing a placement new.
|
|
void *operator new(size_t Bytes, ASTContext &C,
|
|
unsigned Alignment = Decl::Alignment);
|
|
void *operator new(size_t Bytes, void *Mem) {
|
|
assert(Mem);
|
|
return Mem;
|
|
}
|
|
};
|
|
|
|
/// ImportDecl - This represents a single import declaration, e.g.:
|
|
/// import swift
|
|
/// import swift.int
|
|
class ImportDecl : public Decl {
|
|
public:
|
|
typedef std::pair<Identifier, SourceLoc> AccessPathElement;
|
|
|
|
private:
|
|
SourceLoc ImportLoc;
|
|
|
|
/// The number of elements in this path.
|
|
unsigned NumPathElements;
|
|
|
|
AccessPathElement *getPathBuffer() {
|
|
return reinterpret_cast<AccessPathElement*>(this+1);
|
|
}
|
|
const AccessPathElement *getPathBuffer() const {
|
|
return reinterpret_cast<const AccessPathElement*>(this+1);
|
|
}
|
|
|
|
ImportDecl(DeclContext *DC, SourceLoc ImportLoc,
|
|
ArrayRef<AccessPathElement> Path);
|
|
|
|
public:
|
|
static ImportDecl *create(ASTContext &C, DeclContext *DC,
|
|
SourceLoc ImportLoc,
|
|
ArrayRef<AccessPathElement> Path);
|
|
|
|
ArrayRef<AccessPathElement> getAccessPath() const {
|
|
return ArrayRef<AccessPathElement>(getPathBuffer(), NumPathElements);
|
|
}
|
|
|
|
SourceLoc getLocStart() const { return ImportLoc; }
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Import;
|
|
}
|
|
static bool classof(const ImportDecl *D) { return true; }
|
|
};
|
|
|
|
/// ExtensionDecl - This represents a type extension containing methods
|
|
/// associated with the type. This is not a ValueDecl and has no Type because
|
|
/// there are no runtime values of the Extension's type.
|
|
class ExtensionDecl : public Decl, public DeclContext {
|
|
SourceLoc ExtensionLoc; // Location of 'extension' keyword.
|
|
|
|
/// ExtendedType - The type being extended.
|
|
Type ExtendedType;
|
|
ArrayRef<Decl*> Members;
|
|
public:
|
|
|
|
ExtensionDecl(SourceLoc ExtensionLoc, Type ExtendedType,
|
|
ArrayRef<Decl*> Members, DeclContext *Parent)
|
|
: Decl(DeclKind::Extension, Parent),
|
|
DeclContext(DeclContextKind::ExtensionDecl, Parent),
|
|
ExtensionLoc(ExtensionLoc),
|
|
ExtendedType(ExtendedType), Members(Members) {
|
|
}
|
|
|
|
SourceLoc getExtensionLoc() const { return ExtensionLoc; }
|
|
SourceLoc getLocStart() const { return ExtensionLoc; }
|
|
Type getExtendedType() const { return ExtendedType; }
|
|
ArrayRef<Decl*> getMembers() const { return Members; }
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::Extension;
|
|
}
|
|
static bool classof(const DeclContext *C) {
|
|
return C->getContextKind() == DeclContextKind::ExtensionDecl;
|
|
}
|
|
static bool classof(const ExtensionDecl *D) { return true; }
|
|
};
|
|
|
|
// PatternBindingDecl - This decl contains a pattern and optional initializer
|
|
// for a set of one or more VarDecls declared together. (For example, in
|
|
// "var (a,b) = foo()", this contains the pattern "(a,b)" and the intializer
|
|
// "foo()". The same applies to simpler declarations like "var a = foo()".)
|
|
class PatternBindingDecl : public Decl {
|
|
SourceLoc VarLoc; // Location of the 'var' keyword
|
|
Pattern *Pat; // The pattern which this decl binds
|
|
Expr *Init; // Initializer for the variables
|
|
|
|
friend class Decl;
|
|
|
|
/// \brief Update the DeclContext for any variables in the pattern to
|
|
/// refer to the same DeclContext as this declaration.
|
|
void updateDeclContextForVars();
|
|
|
|
public:
|
|
PatternBindingDecl(SourceLoc VarLoc, Pattern *Pat, Expr *E,
|
|
DeclContext *Parent)
|
|
: Decl(DeclKind::PatternBinding, Parent), VarLoc(VarLoc), Pat(Pat),
|
|
Init(E) {
|
|
}
|
|
|
|
SourceLoc getVarLoc() const { return VarLoc; }
|
|
SourceLoc getLocStart() const { return VarLoc; }
|
|
|
|
Pattern *getPattern() const { return Pat; }
|
|
|
|
Expr *getInit() const { return Init; }
|
|
void setInit(Expr *E) { Init = E; }
|
|
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::PatternBinding;
|
|
}
|
|
static bool classof(const PatternBindingDecl *D) { return true; }
|
|
|
|
};
|
|
|
|
/// NamedDecl - An abstract base class for declarations with names.
|
|
class NamedDecl : public Decl {
|
|
Identifier Name;
|
|
const DeclAttributes *Attrs;
|
|
static const DeclAttributes EmptyAttrs;
|
|
|
|
protected:
|
|
NamedDecl(DeclKind K, DeclContext *DC, Identifier name)
|
|
: Decl(K, DC), Name(name), Attrs(&EmptyAttrs) {
|
|
}
|
|
|
|
public:
|
|
Identifier getName() const { return Name; }
|
|
bool isOperator() const { return Name.isOperator(); }
|
|
|
|
DeclAttributes &getMutableAttrs();
|
|
const DeclAttributes &getAttrs() const { return *Attrs; }
|
|
|
|
Resilience getResilienceFrom(Component *C) const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_NamedDecl &&
|
|
D->getKind() <= DeclKind::Last_NamedDecl;
|
|
}
|
|
static bool classof(const NamedDecl *D) { return true; }
|
|
};
|
|
|
|
/// ValueDecl - All named decls that are values in the language. These can
|
|
/// have a type, etc.
|
|
class ValueDecl : public NamedDecl {
|
|
Type Ty;
|
|
|
|
protected:
|
|
ValueDecl(DeclKind K, DeclContext *DC, bool IsModuleScope,
|
|
Identifier name, Type ty)
|
|
: NamedDecl(K, DC, name), Ty(ty) {
|
|
ValueDeclBits.IsModuleScope = IsModuleScope;
|
|
ValueDeclBits.NeverUsedAsLValue = false;
|
|
ValueDeclBits.HasFixedLifetime = false;
|
|
}
|
|
|
|
public:
|
|
|
|
/// 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 isDefinition() const;
|
|
|
|
bool hasType() const { return !Ty.isNull(); }
|
|
Type getType() const {
|
|
assert(!Ty.isNull() && "declaration has no type set yet");
|
|
return Ty;
|
|
}
|
|
|
|
/// Set the type of this declaration for the first time.
|
|
void setType(Type T) {
|
|
assert(Ty.isNull() && "changing type of declaration");
|
|
Ty = T;
|
|
}
|
|
|
|
/// Overwrite the type of this declaration.
|
|
void overwriteType(Type T) {
|
|
Ty = T;
|
|
}
|
|
|
|
/// getTypeOfReference - Returns the type that would arise from a
|
|
/// normal reference to this declaration. For isReferencedAsLValue()'d decls,
|
|
/// this returns a reference to the value's type. For non-lvalue decls, this
|
|
/// just returns the decl's type.
|
|
Type getTypeOfReference() const;
|
|
|
|
/// isReferencedAsLValue - Returns 'true' if references to this
|
|
/// declaration are l-values.
|
|
bool isReferencedAsLValue() const {
|
|
return getKind() == DeclKind::Var;
|
|
}
|
|
|
|
void setHasFixedLifetime(bool flag) {
|
|
ValueDeclBits.HasFixedLifetime = flag;
|
|
}
|
|
void setNeverUsedAsLValue(bool flag) {
|
|
ValueDeclBits.NeverUsedAsLValue = flag;
|
|
}
|
|
|
|
bool hasFixedLifetime() const {
|
|
return ValueDeclBits.HasFixedLifetime;
|
|
}
|
|
bool isNeverUsedAsLValue() const {
|
|
return ValueDeclBits.NeverUsedAsLValue;
|
|
}
|
|
|
|
bool isModuleScope() const {
|
|
return ValueDeclBits.IsModuleScope;
|
|
}
|
|
void setModuleScope(bool flag) {
|
|
ValueDeclBits.IsModuleScope = flag;
|
|
}
|
|
|
|
|
|
/// isInstanceMember - Determine whether this value is an instance member
|
|
/// of a oneof or protocol.
|
|
bool isInstanceMember() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() >= DeclKind::First_ValueDecl &&
|
|
D->getKind() <= DeclKind::Last_ValueDecl;
|
|
}
|
|
static bool classof(const ValueDecl *D) { return true; }
|
|
};
|
|
|
|
/// TypeAliasDecl - This is a declaration of a typealias, for example:
|
|
///
|
|
/// typealias foo : int
|
|
///
|
|
/// TypeAliasDecl's always have 'MetaTypeType' type.
|
|
///
|
|
class TypeAliasDecl : public ValueDecl {
|
|
/// The type that represents this (sugared) name alias.
|
|
mutable NameAliasType *AliasTy;
|
|
|
|
SourceLoc TypeAliasLoc;
|
|
Type UnderlyingTy;
|
|
|
|
public:
|
|
TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
|
|
Type Underlyingty, DeclContext *DC,
|
|
bool IsModuleScope);
|
|
|
|
SourceLoc getTypeAliasLoc() const { return TypeAliasLoc; }
|
|
void setTypeAliasLoc(SourceLoc loc) { TypeAliasLoc = loc; }
|
|
|
|
/// hasUnderlyingType - Returns whether the underlying type has been set.
|
|
bool hasUnderlyingType() const {
|
|
return !UnderlyingTy.isNull();
|
|
}
|
|
|
|
/// getUnderlyingType - Returns the underlying type, which is
|
|
/// assumed to have been set.
|
|
Type getUnderlyingType() const {
|
|
assert(!UnderlyingTy.isNull() && "getting invalid underlying type");
|
|
return UnderlyingTy;
|
|
}
|
|
|
|
/// setUnderlyingType - Set the underlying type. This is meant to
|
|
/// be used when resolving an unresolved type name during name-binding.
|
|
void setUnderlyingType(Type T) {
|
|
assert(UnderlyingTy.isNull() && "changing underlying type of type-alias");
|
|
UnderlyingTy = T;
|
|
}
|
|
|
|
/// overwriteUnderlyingType - Actually change the underlying type.
|
|
/// Typically it is overwritten to an error type. It's possible for
|
|
/// type canonicalization to not see these changes.
|
|
void overwriteUnderlyingType(Type T) {
|
|
UnderlyingTy = T;
|
|
}
|
|
|
|
SourceLoc getLocStart() const { return TypeAliasLoc; }
|
|
|
|
/// getAliasType - Return the sugared version of this decl as a Type.
|
|
NameAliasType *getAliasType() const;
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::TypeAlias;
|
|
}
|
|
static bool classof(const TypeAliasDecl *D) { return true; }
|
|
};
|
|
|
|
|
|
/// VarDecl - 'var' declaration.
|
|
class VarDecl : public ValueDecl {
|
|
private:
|
|
SourceLoc VarLoc; // Location of the 'var' token.
|
|
|
|
struct GetSetRecord {
|
|
SourceRange Braces;
|
|
FuncDecl *Get; // User-defined getter
|
|
FuncDecl *Set; // User-defined setter
|
|
};
|
|
|
|
GetSetRecord *GetSet;
|
|
|
|
friend class Decl;
|
|
void updateDeclContextForGetSet();
|
|
|
|
public:
|
|
VarDecl(SourceLoc VarLoc, Identifier Name, Type Ty, DeclContext *DC,
|
|
bool IsModuleScope)
|
|
: ValueDecl(DeclKind::Var, DC, IsModuleScope, Name, Ty),
|
|
VarLoc(VarLoc), GetSet() {}
|
|
|
|
/// getVarLoc - The location of the 'var' token.
|
|
SourceLoc getVarLoc() const { return VarLoc; }
|
|
|
|
SourceLoc getLocStart() const { return VarLoc; }
|
|
|
|
/// \brief Determine whether this variable is actually a property, which
|
|
/// has no storage but does have a user-defined getter or setter.
|
|
bool isProperty() const { return GetSet != nullptr; }
|
|
|
|
/// \brief Make this variable into a property, providing a getter and
|
|
/// setter.
|
|
void setProperty(ASTContext &Context, SourceLoc LBraceLoc, FuncDecl *Get,
|
|
FuncDecl *Set, SourceLoc RBraceLoc);
|
|
|
|
/// \brief Retrieve the getter used to access the value of this variable.
|
|
FuncDecl *getGetter() const { return GetSet? GetSet->Get : nullptr; }
|
|
|
|
/// \brief Retrieve the setter used to mutate the value of this variable.
|
|
FuncDecl *getSetter() const { return GetSet? GetSet->Set : nullptr; }
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) { return D->getKind() == DeclKind::Var; }
|
|
static bool classof(const VarDecl *D) { return true; }
|
|
};
|
|
|
|
|
|
/// FuncDecl - 'func' declaration.
|
|
class FuncDecl : public ValueDecl {
|
|
SourceLoc StaticLoc; // Location of the 'static' token or invalid.
|
|
SourceLoc FuncLoc; // Location of the 'func' token.
|
|
FuncExpr *Body;
|
|
public:
|
|
FuncDecl(SourceLoc StaticLoc, SourceLoc FuncLoc, Identifier Name,
|
|
Type Ty, FuncExpr *Body, DeclContext *DC,
|
|
bool IsModuleScope)
|
|
: ValueDecl(DeclKind::Func, DC, IsModuleScope, Name, Ty),
|
|
StaticLoc(StaticLoc), FuncLoc(FuncLoc), Body(Body) {
|
|
}
|
|
|
|
bool isStatic() const { return StaticLoc.isValid(); }
|
|
|
|
FuncExpr *getBody() const { return Body; }
|
|
void setBody(FuncExpr *NewBody) { Body = NewBody; }
|
|
|
|
|
|
/// getExtensionType - If this is a method in a type extension for some type,
|
|
/// return that type, otherwise return Type().
|
|
Type getExtensionType() const;
|
|
|
|
/// 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 computeThisType() const;
|
|
|
|
/// getImplicitThisDecl - If this FuncDecl is a non-static method in an
|
|
/// extension context, it will have a 'this' argument. This method returns it
|
|
/// if present, or returns null if not.
|
|
VarDecl *getImplicitThisDecl();
|
|
const VarDecl *getImplicitThisDecl() const {
|
|
return const_cast<FuncDecl*>(this)->getImplicitThisDecl();
|
|
}
|
|
|
|
SourceLoc getStaticLoc() const { return StaticLoc; }
|
|
SourceLoc getFuncLoc() const { return FuncLoc; }
|
|
|
|
SourceLoc getLocStart() const {
|
|
return StaticLoc.isValid() ? StaticLoc : FuncLoc;
|
|
}
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) { return D->getKind() == DeclKind::Func; }
|
|
static bool classof(const FuncDecl *D) { return true; }
|
|
};
|
|
|
|
/// OneOfElementDecl - This represents an element of a 'oneof' declaration, e.g.
|
|
/// X and Y in:
|
|
/// oneof d { X : int, Y : int, Z }
|
|
/// The type of a OneOfElementDecl is always the OneOfType for the containing
|
|
/// oneof.
|
|
class OneOfElementDecl : public ValueDecl {
|
|
SourceLoc IdentifierLoc;
|
|
|
|
/// ArgumentType - This is the type specified with the oneof element. For
|
|
/// example 'int' in the Y example above. This is null if there is no type
|
|
/// associated with this element (such as in the Z example).
|
|
Type ArgumentType;
|
|
|
|
public:
|
|
OneOfElementDecl(SourceLoc IdentifierLoc, Identifier Name, Type Ty,
|
|
Type ArgumentType, DeclContext *DC,
|
|
bool IsModuleScope)
|
|
: ValueDecl(DeclKind::OneOfElement, DC, IsModuleScope, Name, Ty),
|
|
IdentifierLoc(IdentifierLoc), ArgumentType(ArgumentType) {}
|
|
|
|
Type getArgumentType() const { return ArgumentType; }
|
|
|
|
SourceLoc getIdentifierLoc() const { return IdentifierLoc; }
|
|
SourceLoc getLocStart() const { return IdentifierLoc; }
|
|
|
|
// Implement isa/cast/dyncast/etc.
|
|
static bool classof(const Decl *D) {
|
|
return D->getKind() == DeclKind::OneOfElement;
|
|
}
|
|
static bool classof(const OneOfElementDecl *D) { return true; }
|
|
|
|
};
|
|
|
|
inline void Decl::setDeclContext(DeclContext *DC) {
|
|
Context = DC;
|
|
if (PatternBindingDecl *PBD = dyn_cast<PatternBindingDecl>(this))
|
|
PBD->updateDeclContextForVars();
|
|
else if (VarDecl *Var = dyn_cast<VarDecl>(this))
|
|
Var->updateDeclContextForGetSet();
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif
|