Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -852,10 +852,11 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
BridgedStringRef cName,
bool underscored);

SWIFT_NAME(
"BridgedCustomAttr.createParsed(_:atLoc:type:initContext:argumentList:)")
SWIFT_NAME("BridgedCustomAttr.createParsed(atLoc:type:declContext:initContext:"
"argumentList:)")
BridgedCustomAttr BridgedCustomAttr_createParsed(
BridgedASTContext cContext, swift::SourceLoc atLoc, BridgedTypeRepr cType,
swift::SourceLoc atLoc, BridgedTypeRepr cType,
BridgedDeclContext cDeclContext,
BridgedNullableCustomAttributeInitializer cInitContext,
BridgedNullableArgumentList cArgumentList);

Expand Down
41 changes: 36 additions & 5 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class GenericFunctionType;
class LazyConformanceLoader;
class LazyMemberLoader;
class ModuleDecl;
class NominalTypeDecl;
class PatternBindingInitializer;
class TrailingWhereClause;
class TypeExpr;
Expand Down Expand Up @@ -2272,34 +2273,63 @@ class ClangImporterSynthesizedTypeAttr : public DeclAttribute {
}
};

/// The owning decl for a given custom attribute, or a DeclContext for a
/// custom attribute in e.g a closure or inheritance clause.
class CustomAttrOwner final {
llvm::PointerUnion<Decl *, DeclContext *> Owner;

public:
CustomAttrOwner() : Owner(nullptr) {}
CustomAttrOwner(Decl *D) : Owner(D) {}
CustomAttrOwner(DeclContext *DC) : Owner(DC) {}

/// If the owner is a declaration, returns it, \c nullptr otherwise.
Decl *getAsDecl() const { return Owner.dyn_cast<Decl *>(); }

/// Retrieve the DeclContext for the CustomAttr.
DeclContext *getDeclContext() const;
};

/// Defines a custom attribute.
class CustomAttr final : public DeclAttribute {
TypeExpr *typeExpr;
ArgumentList *argList;
CustomAttrOwner owner;
CustomAttributeInitializer *initContext;
Expr *semanticInit = nullptr;

mutable unsigned isArgUnsafeBit : 1;

CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
CustomAttributeInitializer *initContext, ArgumentList *argList,
bool implicit);
CustomAttrOwner owner, CustomAttributeInitializer *initContext,
ArgumentList *argList, bool implicit);

public:
static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
bool implicit = false) {
return create(ctx, atLoc, type, /*initContext*/ nullptr,
CustomAttrOwner owner, bool implicit = false) {
return create(ctx, atLoc, type, owner, /*initContext*/ nullptr,
/*argList*/ nullptr, implicit);
}

static CustomAttr *create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
CustomAttrOwner owner,
CustomAttributeInitializer *initContext,
ArgumentList *argList, bool implicit = false);

TypeExpr *getTypeExpr() const { return typeExpr; }
TypeRepr *getTypeRepr() const;
Type getType() const;

/// Retrieve the Decl or DeclContext owner for the attribute.
CustomAttrOwner getOwner() const { return owner; }
void setOwner(CustomAttrOwner newOwner) { owner = newOwner; }

ASTContext &getASTContext() const;

/// Retrieve the NominalTypeDecl the CustomAttr refers to, or \c nullptr if
/// it doesn't refer to one (which can be the case for e.g macro attrs).
NominalTypeDecl *getNominalDecl() const;

/// Destructure an attribute's type repr for a macro reference.
///
/// For a 1-level member type repr whose base and member are both identifier
Expand Down Expand Up @@ -2336,7 +2366,8 @@ class CustomAttr final : public DeclAttribute {
CustomAttr *clone(ASTContext &ctx) const {
assert(argList == nullptr &&
"Cannot clone custom attribute with an argument list");
return create(ctx, AtLoc, getTypeExpr(), initContext, argList, isImplicit());
return create(ctx, AtLoc, getTypeExpr(), owner, initContext, argList,
isImplicit());
}

bool canClone() const { return argList == nullptr; }
Expand Down
11 changes: 5 additions & 6 deletions include/swift/AST/NameLookupRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,19 +350,18 @@ class TypeDeclsFromWhereClauseRequest :

/// Request the nominal type declaration to which the given custom
/// attribute refers.
class CustomAttrNominalRequest :
public SimpleRequest<CustomAttrNominalRequest,
NominalTypeDecl *(CustomAttr *, DeclContext *),
RequestFlags::Cached> {
class CustomAttrNominalRequest
: public SimpleRequest<CustomAttrNominalRequest,
NominalTypeDecl *(CustomAttr *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
NominalTypeDecl *
evaluate(Evaluator &evaluator, CustomAttr *attr, DeclContext *dc) const;
NominalTypeDecl *evaluate(Evaluator &evaluator, CustomAttr *attr) const;

public:
// Caching
Expand Down
3 changes: 1 addition & 2 deletions include/swift/AST/NameLookupTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ SWIFT_REQUEST(NameLookup, AnyObjectLookupRequest,
QualifiedLookupResult(const DeclContext *, DeclName, NLOptions),
Uncached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, CustomAttrNominalRequest,
NominalTypeDecl *(CustomAttr *, DeclContext *), Cached,
NoLocationInfo)
NominalTypeDecl *(CustomAttr *), Cached, NoLocationInfo)
SWIFT_REQUEST(NameLookup, DirectLookupRequest,
TinyPtrVector<ValueDecl *>(DirectLookupDescriptor), Uncached,
NoLocationInfo)
Expand Down
24 changes: 22 additions & 2 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3053,16 +3053,26 @@ bool ImplementsAttr::isEquivalent(const ImplementsAttr *other,
&& getProtocol(DC) == other->getProtocol(DC);
}

DeclContext *CustomAttrOwner::getDeclContext() const {
ASSERT(!Owner.isNull());
if (auto *D = getAsDecl())
return D->getDeclContext();

return Owner.dyn_cast<DeclContext *>();
}

CustomAttr::CustomAttr(SourceLoc atLoc, SourceRange range, TypeExpr *type,
CustomAttrOwner owner,
CustomAttributeInitializer *initContext,
ArgumentList *argList, bool implicit)
: DeclAttribute(DeclAttrKind::Custom, atLoc, range, implicit),
typeExpr(type), argList(argList), initContext(initContext) {
typeExpr(type), argList(argList), owner(owner), initContext(initContext) {
assert(type);
isArgUnsafeBit = false;
}

CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
CustomAttrOwner owner,
CustomAttributeInitializer *initContext,
ArgumentList *argList, bool implicit) {
assert(type);
Expand All @@ -3071,7 +3081,7 @@ CustomAttr *CustomAttr::create(ASTContext &ctx, SourceLoc atLoc, TypeExpr *type,
range.End = argList->getEndLoc();

return new (ctx)
CustomAttr(atLoc, range, type, initContext, argList, implicit);
CustomAttr(atLoc, range, type, owner, initContext, argList, implicit);
}

std::pair<UnqualifiedIdentTypeRepr *, DeclRefTypeRepr *>
Expand All @@ -3091,6 +3101,16 @@ CustomAttr::destructureMacroRef() {
return {nullptr, nullptr};
}

ASTContext &CustomAttr::getASTContext() const {
return getOwner().getDeclContext()->getASTContext();
}

NominalTypeDecl *CustomAttr::getNominalDecl() const {
auto &eval = getASTContext().evaluator;
auto *mutThis = const_cast<CustomAttr *>(this);
return evaluateOrDefault(eval, CustomAttrNominalRequest{mutThis}, nullptr);
}

TypeRepr *CustomAttr::getTypeRepr() const { return typeExpr->getTypeRepr(); }
Type CustomAttr::getType() const { return typeExpr->getInstanceType(); }

Expand Down
9 changes: 6 additions & 3 deletions lib/AST/Bridging/DeclAttributeBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,15 @@ BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
}

BridgedCustomAttr BridgedCustomAttr_createParsed(
BridgedASTContext cContext, SourceLoc atLoc, BridgedTypeRepr cType,
SourceLoc atLoc, BridgedTypeRepr cType, BridgedDeclContext cDeclContext,
BridgedNullableCustomAttributeInitializer cInitContext,
BridgedNullableArgumentList cArgumentList) {
ASTContext &context = cContext.unbridged();
DeclContext *DC = cDeclContext.unbridged();
ASTContext &context = DC->getASTContext();
// Note we set a DeclContext as the owner, which we'll change to the attached
// Decl if necessary when attaching the attributes.
return CustomAttr::create(
context, atLoc, new (context) TypeExpr(cType.unbridged()),
context, atLoc, new (context) TypeExpr(cType.unbridged()), /*owner*/ DC,
cInitContext.unbridged(), cArgumentList.unbridged());
}

Expand Down
11 changes: 4 additions & 7 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ void Decl::attachParsedAttrs(DeclAttributes attrs) {
attr->setOriginalDeclaration(this);
for (auto attr : attrs.getAttributes<ABIAttr, /*AllowInvalid=*/true>())
recordABIAttr(attr);
for (auto *attr : attrs.getAttributes<CustomAttr>())
attr->setOwner(this);

// @implementation requires an explicit @objc attribute, but
// @_objcImplementation didn't. Insert one if necessary.
Expand Down Expand Up @@ -573,8 +575,7 @@ Type Decl::getResolvedCustomAttrType(CustomAttr *attr) const {
return ty;

auto dc = getDeclContext();
auto *nominal = evaluateOrDefault(
getASTContext().evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
auto *nominal = attr->getNominalDecl();
if (!nominal)
return Type();

Expand Down Expand Up @@ -8703,11 +8704,7 @@ VarDecl::getAttachedPropertyWrapperTypeInfo(unsigned i) const {
if (i >= attrs.size())
return PropertyWrapperTypeInfo();

auto attr = attrs[i];
auto dc = getDeclContext();
ASTContext &ctx = getASTContext();
nominal = evaluateOrDefault(
ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr);
nominal = attrs[i]->getNominalDecl();
}

if (!nominal)
Expand Down
35 changes: 30 additions & 5 deletions lib/AST/NameLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3971,18 +3971,34 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
parsedGenericParams->getRAngleLoc());
}

NominalTypeDecl *
CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
CustomAttr *attr, DeclContext *dc) const {
static bool shouldPreferPropertyWrapperOverMacro(CustomAttrOwner owner) {
// If we have a VarDecl in a local context, prefer to use a property wrapper
// if one exists. This is necessary since we don't properly support peer
// declarations in local contexts, so want to use a property wrapper if one
// exists.
if (auto *D = dyn_cast_or_null<VarDecl>(owner.getAsDecl())) {
if (D->getDeclContext()->isLocalContext())
return true;
}
return false;
}

NominalTypeDecl *CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
CustomAttr *attr) const {
auto owner = attr->getOwner();
auto *dc = owner.getDeclContext();

// Look for names at module scope, so we don't trigger name lookup for
// nested scopes. At this point, we're looking to see whether there are
// any suitable macros.
// any suitable macros. If we're preferring property wrappers we wait to see
// if any property wrappers are in scope before returning.
auto [module, macro] = attr->destructureMacroRef();
auto moduleName = (module) ? module->getNameRef() : DeclNameRef();
auto macroName = (macro) ? macro->getNameRef() : DeclNameRef();
auto macros = namelookup::lookupMacros(dc, moduleName, macroName,
getAttachedMacroRoles());
if (!macros.empty())
auto shouldPreferPropWrapper = shouldPreferPropertyWrapperOverMacro(owner);
if (!macros.empty() && !shouldPreferPropWrapper)
return nullptr;

// Find the types referenced by the custom attribute.
Expand All @@ -4002,6 +4018,15 @@ CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
auto nominals = resolveTypeDeclsToNominal(evaluator, ctx, decls.first,
ResolveToNominalOptions(),
modulesFound, anyObject);
// If we're preferring property wrappers and found a suitable match, continue.
// Otherwise we can bail and resolve as a macro.
if (shouldPreferPropWrapper) {
auto hasPropWrapper = llvm::any_of(nominals, [](NominalTypeDecl *NTD) {
return NTD->getAttrs().hasAttribute<PropertyWrapperAttr>();
});
if (!macros.empty() && !hasPropWrapper)
return nullptr;
}
if (nominals.size() == 1 && !isa<ProtocolDecl>(nominals.front()))
return nominals.front();

Expand Down
2 changes: 1 addition & 1 deletion lib/ASTGen/Sources/ASTGen/DeclAttrs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2285,9 +2285,9 @@ extension ASTGenVisitor {
}

return .createParsed(
self.ctx,
atLoc: self.generateSourceLoc(node.atSign),
type: type,
declContext: declContext,
initContext: initContext.asNullable,
argumentList: argList.asNullable
)
Expand Down
4 changes: 2 additions & 2 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6262,8 +6262,8 @@ void cloneImportedAttributes(ValueDecl *fromDecl, ValueDecl* toDecl) {
case DeclAttrKind::Custom: {
CustomAttr *cAttr = cast<CustomAttr>(attr);
attrs.add(CustomAttr::create(context, SourceLoc(), cAttr->getTypeExpr(),
cAttr->getInitContext(), cAttr->getArgs(),
true));
/*owner*/ toDecl, cAttr->getInitContext(),
cAttr->getArgs(), /*implicit*/ true));
break;
}
case DeclAttrKind::DiscardableResult: {
Expand Down
8 changes: 6 additions & 2 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8885,7 +8885,10 @@ void ClangImporter::Implementation::importNontrivialAttribute(
SmallVector<DeclAttribute *, 2> attrs(decl->getAttrs().begin(),
decl->getAttrs().end());
for (auto attr : attrs) {
MappedDecl->getAttrs().add(cached ? attr->clone(SwiftContext) : attr);
auto *newAttr = cached ? attr->clone(SwiftContext) : attr;
if (auto *CA = dyn_cast<CustomAttr>(newAttr))
CA->setOwner(MappedDecl);
MappedDecl->getAttrs().add(newAttr);
}
}
break;
Expand Down Expand Up @@ -8933,7 +8936,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {

if (Type mainActorType = SwiftContext.getMainActorType()) {
auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext);
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr);
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr,
/*owner*/ MappedDecl);
MappedDecl->getAttrs().add(attr);
seenMainActorAttr = swiftAttr;
}
Expand Down
8 changes: 5 additions & 3 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4215,10 +4215,12 @@ ParserResult<CustomAttr> Parser::parseCustomAttribute(SourceLoc atLoc) {
"Cannot parse a trailing closure here");
}

// Form the attribute.
// Form the attribute. We set a DeclContext as the owner, which we'll change
// to the attached Decl if necessary when attaching the attributes.
auto *TE = new (Context) TypeExpr(type.get());
auto *customAttr = CustomAttr::create(Context, atLoc, TE, initContext,
argList);
auto *customAttr =
CustomAttr::create(Context, atLoc, TE,
/*owner*/ CurDeclContext, initContext, argList);
if (status.hasCodeCompletion() && CodeCompletionCallbacks) {
CodeCompletionCallbacks->setCompletingInAttribute(customAttr);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/CSSyntacticElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2595,7 +2595,8 @@ static void applySolutionToClosurePropertyWrappers(ClosureExpr *closure,
auto &context = wrappedValueVar->getASTContext();
auto *typeExpr = TypeExpr::createImplicit(backingType, context);
auto *attr =
CustomAttr::create(context, SourceLoc(), typeExpr, /*implicit=*/true);
CustomAttr::create(context, SourceLoc(), typeExpr,
/*owner*/ wrappedValueVar, /*implicit=*/true);
wrappedValueVar->getAttrs().add(attr);
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/CodeSynthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ static ParamDecl *createMemberwiseInitParameter(DeclContext *DC,
// Attach a result builder attribute if needed.
if (resultBuilderType) {
auto typeExpr = TypeExpr::createImplicit(resultBuilderType, ctx);
auto attr =
CustomAttr::create(ctx, SourceLoc(), typeExpr, /*implicit=*/true);
auto attr = CustomAttr::create(ctx, SourceLoc(), typeExpr, /*owner*/ arg,
/*implicit=*/true);
arg->getAttrs().add(attr);
}

Expand Down
Loading