Skip to content

Commit 8b73c9c

Browse files
authored
Merge pull request #85363 from hamishknight/hattrick
[Sema] Avoid member attribute cycle in ResolveMacroRequest
2 parents 4b4f9f1 + f2b0b92 commit 8b73c9c

File tree

5 files changed

+35
-17
lines changed

5 files changed

+35
-17
lines changed

include/swift/AST/Attr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,10 @@ class CustomAttr final : public DeclAttribute {
23592359

23602360
ASTContext &getASTContext() const;
23612361

2362+
/// If \c true, we should prefer a property wrapper if one exists for the
2363+
/// given attribute over a macro.
2364+
bool shouldPreferPropertyWrapperOverMacro() const;
2365+
23622366
/// Retrieve the NominalTypeDecl the CustomAttr refers to, or \c nullptr if
23632367
/// it doesn't refer to one (which can be the case for e.g macro attrs).
23642368
NominalTypeDecl *getNominalDecl() const;

lib/AST/Attr.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3167,6 +3167,20 @@ ASTContext &CustomAttr::getASTContext() const {
31673167
return getOwner().getDeclContext()->getASTContext();
31683168
}
31693169

3170+
bool CustomAttr::shouldPreferPropertyWrapperOverMacro() const {
3171+
// If we have a VarDecl in a local context, prefer to use a property wrapper
3172+
// if one exists. This is necessary since we don't properly support peer
3173+
// declarations in local contexts, so want to use a property wrapper if one
3174+
// exists.
3175+
if (auto *D = getOwner().getAsDecl()) {
3176+
if ((isa<VarDecl>(D) || isa<PatternBindingDecl>(D)) &&
3177+
D->getDeclContext()->isLocalContext()) {
3178+
return true;
3179+
}
3180+
}
3181+
return false;
3182+
}
3183+
31703184
NominalTypeDecl *CustomAttr::getNominalDecl() const {
31713185
auto &eval = getASTContext().evaluator;
31723186
auto *mutThis = const_cast<CustomAttr *>(this);

lib/AST/NameLookup.cpp

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4020,20 +4020,6 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
40204020
parsedGenericParams->getRAngleLoc());
40214021
}
40224022

4023-
static bool shouldPreferPropertyWrapperOverMacro(CustomAttrOwner owner) {
4024-
// If we have a VarDecl in a local context, prefer to use a property wrapper
4025-
// if one exists. This is necessary since we don't properly support peer
4026-
// declarations in local contexts, so want to use a property wrapper if one
4027-
// exists.
4028-
if (auto *D = owner.getAsDecl()) {
4029-
if ((isa<VarDecl>(D) || isa<PatternBindingDecl>(D)) &&
4030-
D->getDeclContext()->isLocalContext()) {
4031-
return true;
4032-
}
4033-
}
4034-
return false;
4035-
}
4036-
40374023
NominalTypeDecl *CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
40384024
CustomAttr *attr) const {
40394025
auto owner = attr->getOwner();
@@ -4048,7 +4034,7 @@ NominalTypeDecl *CustomAttrNominalRequest::evaluate(Evaluator &evaluator,
40484034
auto macroName = (macro) ? macro->getNameRef() : DeclNameRef();
40494035
auto macros = namelookup::lookupMacros(dc, moduleName, macroName,
40504036
getAttachedMacroRoles());
4051-
auto shouldPreferPropWrapper = shouldPreferPropertyWrapperOverMacro(owner);
4037+
auto shouldPreferPropWrapper = attr->shouldPreferPropertyWrapperOverMacro();
40524038
if (!macros.empty() && !shouldPreferPropWrapper)
40534039
return nullptr;
40544040

lib/Sema/TypeCheckMacros.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2242,8 +2242,12 @@ ResolveMacroRequest::evaluate(Evaluator &evaluator,
22422242
// So bail out to prevent diagnostics from the contraint system.
22432243
if (auto *attr = macroRef.getAttr()) {
22442244
// If we already resolved this CustomAttr to a nominal, this isn't for a
2245-
// macro.
2246-
if (attr->getNominalDecl())
2245+
// macro. This can only currently be the case for property wrappers, so
2246+
// limit the check here to avoid request cycles for member attribute macros
2247+
// in cases where the attribute refers to a nested type in the type it's
2248+
// attached to, since the qualified lookup there needs to expand member
2249+
// attributes.
2250+
if (attr->shouldPreferPropertyWrapperOverMacro() && attr->getNominalDecl())
22472251
return ConcreteDeclRef();
22482252

22492253
auto foundMacros = namelookup::lookupMacros(dc, macroRef.getModuleName(),
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// Make sure we don't end up with a request cycle here, since looking up 'S.Actor'
4+
// requires expanding member attribute macros for 'S'.
5+
@S.Actor
6+
struct S {
7+
@globalActor actor Actor: GlobalActor {
8+
public static let shared = S.Actor()
9+
}
10+
}

0 commit comments

Comments
 (0)