From bbd5dfcfdfcb68dbcc258eb2bc68223648731c22 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Fri, 13 Apr 2012 21:45:27 +0000 Subject: [PATCH] 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 --- docs/LangRef.html | 2 +- include/swift/AST/Decl.h | 19 ++++++++++++++++++- lib/AST/Decl.cpp | 39 ++++++++++++++++++++++++++++++++++++++ lib/Parse/ParseDecl.cpp | 3 ++- lib/Sema/TypeCheckDecl.cpp | 6 ++++++ 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/docs/LangRef.html b/docs/LangRef.html index e7804c16c09..328bd33e975 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -458,7 +458,7 @@

oneof and struct declaration extensions

-

'var' decls are not allowed in a oneof or struct, +

'var' decls that do not have a getter or setter are not allowed in a oneof or struct, data members should be used instead.

diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index e31f6e2c6ce..973827b8b1e 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -104,7 +104,7 @@ public: DeclKind getKind() const { return DeclKind(DeclBits.Kind); } DeclContext *getDeclContext() const { return Context; } - void setDeclContext(DeclContext *DC) { Context = DC; } + void setDeclContext(DeclContext *DC); /// getASTContext - Return the ASTContext that this decl lives in. ASTContext &getASTContext() const { @@ -218,6 +218,12 @@ class PatternBindingDecl : public Decl { 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) @@ -425,6 +431,9 @@ private: GetSetRecord *GetSet; + friend class Decl; + void updateDeclContextForGetSet(); + public: VarDecl(SourceLoc VarLoc, Identifier Name, Type Ty, DeclContext *DC, bool IsModuleScope) @@ -540,6 +549,14 @@ public: }; +inline void Decl::setDeclContext(DeclContext *DC) { + Context = DC; + if (PatternBindingDecl *PBD = dyn_cast(this)) + PBD->updateDeclContextForVars(); + else if (VarDecl *Var = dyn_cast(this)) + Var->updateDeclContextForGetSet(); +} + } // end namespace swift #endif diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 694e6b78014..33b5bf78452 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -146,6 +146,16 @@ void VarDecl::setProperty(ASTContext &Context, SourceLoc LBraceLoc, 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, /// return that type, otherwise return Type(). Type FuncDecl::getExtensionType() const { @@ -212,6 +222,35 @@ VarDecl *FuncDecl::getImplicitThisDecl() { return 0; } +static void updateDeclContextForVarsInPattern(Pattern *P, DeclContext *DC) { + switch (P->getKind()) { + case PatternKind::Any: + break; + + case PatternKind::Named: + cast(P)->getDecl()->setDeclContext(DC); + break; + + case PatternKind::Paren: + updateDeclContextForVarsInPattern(cast(P)->getSubPattern(), + DC); + break; + + case PatternKind::Tuple: + for (auto &Elt : cast(P)->getFields()) + updateDeclContextForVarsInPattern(Elt.getPattern(), DC); + break; + + case PatternKind::Typed: + updateDeclContextForVarsInPattern(cast(P)->getSubPattern(), + DC); + break; + } +} + +void PatternBindingDecl::updateDeclContextForVars() { + updateDeclContextForVarsInPattern(Pat, getDeclContext()); +} //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index c0793ecd642..6b63d37dc5c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -349,7 +349,8 @@ bool Parser::parseDecl(SmallVectorImpl &Entries, unsigned Flags) { // FIXME: Mark decls erroneous. if (isa(D) && !(Flags & PD_AllowTopLevel)) diagnose(D->getLocStart(), diag::decl_inner_scope); - if (isa(D) && (Flags & PD_DisallowVar)) { + if (isa(D) && (Flags & PD_DisallowVar) && + !cast(D)->isProperty()) { diagnose(D->getLocStart(), diag::disallowed_var_decl); } else if (NamedDecl *ND = dyn_cast(D)) { if (ND->isOperator() && (Flags & PD_DisallowOperators)) diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index caace099587..e61c75f6824 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -121,6 +121,12 @@ public: void visitVarDecl(VarDecl *VD) { // Delay type-checking on VarDecls until we see the corresponding // PatternBindingDecl. + if (VD->isProperty()) { + if (FuncDecl *Get = VD->getGetter()) + visitFuncDecl(Get); + if (FuncDecl *Set = VD->getSetter()) + visitFuncDecl(Set); + } } void visitFuncDecl(FuncDecl *FD) {