Allow variables with a getter or setter to be declared in a

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
This commit is contained in:
Doug Gregor
2012-04-13 21:45:27 +00:00
parent 0cc17a2481
commit bbd5dfcfdf
5 changed files with 66 additions and 3 deletions

View File

@@ -458,7 +458,7 @@
<h4 id="decl-extension-oneof-struct"><a href="#decl-oneof">oneof</a> and <a <h4 id="decl-extension-oneof-struct"><a href="#decl-oneof">oneof</a> and <a
href="#decl-struct">struct</a> declaration extensions</h4> href="#decl-struct">struct</a> declaration extensions</h4>
<p>'<a href="#decl-var">var</a>' decls are not allowed in a oneof or struct, <p>'<a href="#decl-var">var</a>' decls that do not have a getter or setter are not allowed in a oneof or struct,
data members should be used instead.</p> data members should be used instead.</p>

View File

@@ -104,7 +104,7 @@ public:
DeclKind getKind() const { return DeclKind(DeclBits.Kind); } DeclKind getKind() const { return DeclKind(DeclBits.Kind); }
DeclContext *getDeclContext() const { return Context; } DeclContext *getDeclContext() const { return Context; }
void setDeclContext(DeclContext *DC) { Context = DC; } void setDeclContext(DeclContext *DC);
/// getASTContext - Return the ASTContext that this decl lives in. /// getASTContext - Return the ASTContext that this decl lives in.
ASTContext &getASTContext() const { ASTContext &getASTContext() const {
@@ -218,6 +218,12 @@ class PatternBindingDecl : public Decl {
Pattern *Pat; // The pattern which this decl binds Pattern *Pat; // The pattern which this decl binds
Expr *Init; // Initializer for the variables 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: public:
PatternBindingDecl(SourceLoc VarLoc, Pattern *Pat, Expr *E, PatternBindingDecl(SourceLoc VarLoc, Pattern *Pat, Expr *E,
DeclContext *Parent) DeclContext *Parent)
@@ -425,6 +431,9 @@ private:
GetSetRecord *GetSet; GetSetRecord *GetSet;
friend class Decl;
void updateDeclContextForGetSet();
public: public:
VarDecl(SourceLoc VarLoc, Identifier Name, Type Ty, DeclContext *DC, VarDecl(SourceLoc VarLoc, Identifier Name, Type Ty, DeclContext *DC,
bool IsModuleScope) bool IsModuleScope)
@@ -540,6 +549,14 @@ public:
}; };
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 } // end namespace swift
#endif #endif

View File

@@ -146,6 +146,16 @@ void VarDecl::setProperty(ASTContext &Context, SourceLoc LBraceLoc,
GetSet->Set = Set; GetSet->Set = Set;
} }
void VarDecl::updateDeclContextForGetSet() {
if (!GetSet)
return;
if (GetSet->Get)
GetSet->Get->setDeclContext(getDeclContext());
if (GetSet->Set)
GetSet->Set->setDeclContext(getDeclContext());
}
/// getExtensionType - If this is a method in a type extension for some type, /// getExtensionType - If this is a method in a type extension for some type,
/// return that type, otherwise return Type(). /// return that type, otherwise return Type().
Type FuncDecl::getExtensionType() const { Type FuncDecl::getExtensionType() const {
@@ -212,6 +222,35 @@ VarDecl *FuncDecl::getImplicitThisDecl() {
return 0; return 0;
} }
static void updateDeclContextForVarsInPattern(Pattern *P, DeclContext *DC) {
switch (P->getKind()) {
case PatternKind::Any:
break;
case PatternKind::Named:
cast<NamedPattern>(P)->getDecl()->setDeclContext(DC);
break;
case PatternKind::Paren:
updateDeclContextForVarsInPattern(cast<ParenPattern>(P)->getSubPattern(),
DC);
break;
case PatternKind::Tuple:
for (auto &Elt : cast<TuplePattern>(P)->getFields())
updateDeclContextForVarsInPattern(Elt.getPattern(), DC);
break;
case PatternKind::Typed:
updateDeclContextForVarsInPattern(cast<TypedPattern>(P)->getSubPattern(),
DC);
break;
}
}
void PatternBindingDecl::updateDeclContextForVars() {
updateDeclContextForVarsInPattern(Pat, getDeclContext());
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@@ -349,7 +349,8 @@ bool Parser::parseDecl(SmallVectorImpl<Decl*> &Entries, unsigned Flags) {
// FIXME: Mark decls erroneous. // FIXME: Mark decls erroneous.
if (isa<ImportDecl>(D) && !(Flags & PD_AllowTopLevel)) if (isa<ImportDecl>(D) && !(Flags & PD_AllowTopLevel))
diagnose(D->getLocStart(), diag::decl_inner_scope); diagnose(D->getLocStart(), diag::decl_inner_scope);
if (isa<VarDecl>(D) && (Flags & PD_DisallowVar)) { if (isa<VarDecl>(D) && (Flags & PD_DisallowVar) &&
!cast<VarDecl>(D)->isProperty()) {
diagnose(D->getLocStart(), diag::disallowed_var_decl); diagnose(D->getLocStart(), diag::disallowed_var_decl);
} else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) { } else if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
if (ND->isOperator() && (Flags & PD_DisallowOperators)) if (ND->isOperator() && (Flags & PD_DisallowOperators))

View File

@@ -121,6 +121,12 @@ public:
void visitVarDecl(VarDecl *VD) { void visitVarDecl(VarDecl *VD) {
// Delay type-checking on VarDecls until we see the corresponding // Delay type-checking on VarDecls until we see the corresponding
// PatternBindingDecl. // PatternBindingDecl.
if (VD->isProperty()) {
if (FuncDecl *Get = VD->getGetter())
visitFuncDecl(Get);
if (FuncDecl *Set = VD->getSetter())
visitFuncDecl(Set);
}
} }
void visitFuncDecl(FuncDecl *FD) { void visitFuncDecl(FuncDecl *FD) {