Skip to content
7 changes: 7 additions & 0 deletions include/swift/AST/Availability.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,13 @@ class AvailabilityInference {

};

/// Given a declaration upon which an availability attribute would appear in
/// concrete syntax, return a declaration to which the parser
/// actually attaches the attribute in the abstract syntax tree. We use this
/// function to determine whether the concrete syntax already has an
/// availability attribute.
const Decl *abstractSyntaxDeclForAvailableAttribute(const Decl *D);

} // end namespace swift

#endif
20 changes: 20 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class TypeAliasDecl;
class TypeLoc;
class Witness;
class TypeResolution;
class TypeRefinementContext;
struct TypeWitnessAndDecl;
class ValueDecl;
enum class OpaqueReadOwnership: uint8_t;
Expand Down Expand Up @@ -4387,6 +4388,25 @@ class InitAccessorReferencedVariablesRequest
bool isCached() const { return true; }
};

/// Expand the children of the type refinement context for the given
/// declaration.
class ExpandChildTypeRefinementContextsRequest
: public SimpleRequest<ExpandChildTypeRefinementContextsRequest,
bool(Decl *, TypeRefinementContext *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

bool evaluate(Evaluator &evaluator, Decl *decl,
TypeRefinementContext *parentTRC) const;

public:
bool isCached() const { return true; }
};

#define SWIFT_TYPEID_ZONE TypeChecker
#define SWIFT_TYPEID_HEADER "swift/AST/TypeCheckerTypeIDZone.def"
#include "swift/Basic/DefineTypeIDZone.h"
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -500,3 +500,6 @@ SWIFT_REQUEST(TypeChecker, InitAccessorReferencedVariablesRequest,
ArrayRef<VarDecl *>(DeclAttribute *, AccessorDecl *,
ArrayRef<Identifier>),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ExpandChildTypeRefinementContextsRequest,
bool(Decl *, TypeRefinementContext *),
Cached, NoLocationInfo)
3 changes: 3 additions & 0 deletions include/swift/AST/TypeRefinementContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,9 @@ class TypeRefinementContext : public ASTAllocated<TypeRefinementContext> {
static StringRef getReasonName(Reason R);
};

void simple_display(llvm::raw_ostream &out,
const TypeRefinementContext *trc);

} // end namespace swift

#endif
30 changes: 30 additions & 0 deletions lib/AST/Availability.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ AvailabilityInference::attrForAnnotatedAvailableRange(const Decl *D,
ASTContext &Ctx) {
const AvailableAttr *bestAvailAttr = nullptr;

D = abstractSyntaxDeclForAvailableAttribute(D);

for (auto Attr : D->getAttrs()) {
auto *AvailAttr = dyn_cast<AvailableAttr>(Attr);
if (AvailAttr == nullptr || !AvailAttr->Introduced.has_value() ||
Expand Down Expand Up @@ -744,3 +746,31 @@ ASTContext::getSwift5PlusAvailability(llvm::VersionTuple swiftVersion) {
Twine("Missing call to getSwiftXYAvailability for Swift ") +
swiftVersion.getAsString());
}

const Decl *
swift::abstractSyntaxDeclForAvailableAttribute(const Decl *ConcreteSyntaxDecl) {
// This function needs to be kept in sync with its counterpart,
// concreteSyntaxDeclForAvailableAttribute().

if (auto *PBD = dyn_cast<PatternBindingDecl>(ConcreteSyntaxDecl)) {
// Existing @available attributes in the AST are attached to VarDecls
// rather than PatternBindingDecls, so we return the first VarDecl for
// the pattern binding declaration.
// This is safe, even though there may be multiple VarDecls, because
// all parsed attribute that appear in the concrete syntax upon on the
// PatternBindingDecl are added to all of the VarDecls for the pattern
// binding.
for (auto index : range(PBD->getNumPatternEntries())) {
if (auto VD = PBD->getAnchoringVarDecl(index))
return VD;
}
} else if (auto *ECD = dyn_cast<EnumCaseDecl>(ConcreteSyntaxDecl)) {
// Similar to the PatternBindingDecl case above, we return the
// first EnumElementDecl.
if (auto *Elem = ECD->getFirstElement()) {
return Elem;
}
}

return ConcreteSyntaxDecl;
}
18 changes: 11 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2079,19 +2079,23 @@ bool VarDecl::isLayoutExposedToClients() const {
if (!parent) return false;
if (isStatic()) return false;

if (!hasStorage() &&
!getAttrs().hasAttribute<LazyAttr>() &&
!hasAttachedPropertyWrapper()) {
return false;
}

auto nominalAccess =
parent->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (!nominalAccess.isPublic()) return false;

return (parent->getAttrs().hasAttribute<FrozenAttr>() ||
parent->getAttrs().hasAttribute<FixedLayoutAttr>());
if (!parent->getAttrs().hasAttribute<FrozenAttr>() &&
!parent->getAttrs().hasAttribute<FixedLayoutAttr>())
return false;

if (!hasStorage() &&
!getAttrs().hasAttribute<LazyAttr>() &&
!hasAttachedPropertyWrapper()) {
return false;
}

return true;
}

/// Check whether the given type representation will be
Expand Down
22 changes: 22 additions & 0 deletions lib/AST/TypeRefinementContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/Stmt.h"
#include "swift/AST/Expr.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeRefinementContext.h"
#include "swift/Basic/SourceManager.h"

Expand Down Expand Up @@ -192,6 +193,18 @@ TypeRefinementContext::findMostRefinedSubContext(SourceLoc Loc,
!rangeContainsTokenLocWithGeneratedSource(SM, SrcRange, Loc))
return nullptr;

// If this context is for a declaration, ensure that we've expanded the
// children of the declaration.
if (Node.getReason() == Reason::Decl ||
Node.getReason() == Reason::DeclImplicit) {
if (auto decl = Node.getAsDecl()) {
ASTContext &ctx = decl->getASTContext();
(void)evaluateOrDefault(
ctx.evaluator, ExpandChildTypeRefinementContextsRequest{decl, this},
false);
}
}

// For the moment, we perform a linear search here, but we can and should
// do something more efficient.
for (TypeRefinementContext *Child : Children) {
Expand Down Expand Up @@ -354,6 +367,10 @@ void TypeRefinementContext::print(raw_ostream &OS, SourceManager &SrcMgr,
OS << "extension." << ED->getExtendedType().getString();
} else if (isa<TopLevelCodeDecl>(D)) {
OS << "<top-level-code>";
} else if (auto PBD = dyn_cast<PatternBindingDecl>(D)) {
if (auto VD = PBD->getAnchoringVarDecl(0)) {
OS << VD->getName();
}
}
}

Expand Down Expand Up @@ -411,3 +428,8 @@ StringRef TypeRefinementContext::getReasonName(Reason R) {

llvm_unreachable("Unhandled Reason in switch.");
}

void swift::simple_display(
llvm::raw_ostream &out, const TypeRefinementContext *trc) {
out << "TRC @" << trc;
}
Loading