Skip to content

[Macros] Improve breaking of cyclic references for member-attribute macros #65410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -7054,6 +7054,28 @@ ERROR(invalid_macro_role_for_macro_syntax,none,
ERROR(macro_cannot_introduce_names,none,
"'%0' macros are not allowed to introduce names", (StringRef))

ERROR(macro_resolve_circular_reference, none,
"circular reference resolving %select{freestanding|attached}0 macro %1",
(bool, DeclName))
NOTE(macro_resolve_circular_reference_through, none,
"while resolving %select{freestanding|attached}0 macro %1",
(bool, DeclName))

ERROR(macro_expand_circular_reference, none,
"circular reference expanding %0 macro %1", (StringRef, DeclName))
NOTE(macro_expand_circular_reference_through, none,
"circular reference expanding %0 macro %1", (StringRef, DeclName))

ERROR(macro_expand_circular_reference_entity, none,
"circular reference expanding %0 macros on %1", (StringRef, DeclName))
NOTE(macro_expand_circular_reference_entity_through, none,
"circular reference expanding %0 macros on %1", (StringRef, DeclName))

ERROR(macro_expand_circular_reference_unnamed, none,
"circular reference expanding %0 macros", (StringRef))
NOTE(macro_expand_circular_reference_unnamed_through, none,
"circular reference expanding %0 macros", (StringRef))

//------------------------------------------------------------------------------
// MARK: Move Only Errors
//------------------------------------------------------------------------------
Expand Down
25 changes: 23 additions & 2 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -3243,6 +3243,12 @@ class UnresolvedMacroReference {
friend llvm::hash_code hash_value(const UnresolvedMacroReference &ref) {
return reinterpret_cast<ptrdiff_t>(ref.pointer.getOpaqueValue());
}

friend SourceLoc extractNearestSourceLoc(
const UnresolvedMacroReference &ref
) {
return ref.getSigilLoc();
}
};

void simple_display(llvm::raw_ostream &out,
Expand All @@ -3252,7 +3258,7 @@ void simple_display(llvm::raw_ostream &out,
class ResolveMacroRequest
: public SimpleRequest<ResolveMacroRequest,
ConcreteDeclRef(UnresolvedMacroReference,
DeclContext *),
const Decl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;
Expand All @@ -3262,10 +3268,13 @@ class ResolveMacroRequest

ConcreteDeclRef
evaluate(Evaluator &evaluator, UnresolvedMacroReference macroRef,
DeclContext *dc) const;
const Decl *decl) const;

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

void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

class ResolveTypeEraserTypeRequest
Expand Down Expand Up @@ -3917,6 +3926,8 @@ class ExpandMacroExpansionDeclRequest

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand all accessor macros attached to the given declaration.
Expand All @@ -3937,6 +3948,8 @@ class ExpandAccessorMacros

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand all conformance macros attached to the given declaration.
Expand All @@ -3957,6 +3970,8 @@ class ExpandConformanceMacros

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand all member attribute macros attached to the given
Expand All @@ -3977,6 +3992,8 @@ class ExpandMemberAttributeMacros

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Expand synthesized member macros attached to the given declaration.
Expand All @@ -3996,6 +4013,8 @@ class ExpandSynthesizedMemberMacroRequest

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Represent a loaded plugin either an in-process library or an executable.
Expand Down Expand Up @@ -4050,6 +4069,8 @@ class ExpandPeerMacroRequest

public:
bool isCached() const { return true; }
void diagnoseCycle(DiagnosticEngine &diags) const;
void noteCycleStep(DiagnosticEngine &diags) const;
};

/// Resolve an external macro given its module and type name.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ SWIFT_REQUEST(TypeChecker, ResolveImplicitMemberRequest,
evaluator::SideEffect(NominalTypeDecl *, ImplicitMemberAction),
Uncached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveMacroRequest,
ConcreteDeclRef(UnresolvedMacroReference, DeclContext *),
ConcreteDeclRef(UnresolvedMacroReference, const Decl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, ResolveTypeEraserTypeRequest,
Type(ProtocolDecl *, TypeEraserAttr *),
Expand Down
2 changes: 1 addition & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ void Decl::forEachAttachedMacro(MacroRole role,
MacroDecl *Decl::getResolvedMacro(CustomAttr *customAttr) const {
auto declRef = evaluateOrDefault(
getASTContext().evaluator,
ResolveMacroRequest{customAttr, getDeclContext()},
ResolveMacroRequest{customAttr, this},
ConcreteDeclRef());

return dyn_cast_or_null<MacroDecl>(declRef.getDecl());
Expand Down
153 changes: 153 additions & 0 deletions lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1795,3 +1795,156 @@ bool swift::operator==(MacroRoles lhs, MacroRoles rhs) {
llvm::hash_code swift::hash_value(MacroRoles roles) {
return roles.toRaw();
}

static bool isAttachedSyntax(const UnresolvedMacroReference &ref) {
return ref.getAttr() != nullptr;
}

void ResolveMacroRequest::diagnoseCycle(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto macroRef = std::get<0>(storage);
diags.diagnose(macroRef.getSigilLoc(), diag::macro_resolve_circular_reference,
isAttachedSyntax(macroRef),
macroRef.getMacroName().getFullName());
}

void ResolveMacroRequest::noteCycleStep(DiagnosticEngine &diags) const {
const auto &storage = getStorage();
auto macroRef = std::get<0>(storage);
diags.diagnose(macroRef.getSigilLoc(),
diag::macro_resolve_circular_reference_through,
isAttachedSyntax(macroRef),
macroRef.getMacroName().getFullName());
}

void ExpandMacroExpansionDeclRequest::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getPoundLoc(),
diag::macro_expand_circular_reference,
"freestanding",
decl->getMacroName().getFullName());
}

void ExpandMacroExpansionDeclRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getPoundLoc(),
diag::macro_expand_circular_reference_through,
"freestanding",
decl->getMacroName().getFullName());
}

void ExpandAccessorMacros::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity,
"accessor",
decl->getName());
}

void ExpandAccessorMacros::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity_through,
"accessor",
decl->getName());
}

void ExpandConformanceMacros::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity,
"conformance",
decl->getName());
}

void ExpandConformanceMacros::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity_through,
"conformance",
decl->getName());
}

void ExpandMemberAttributeMacros::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity,
"member attribute",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed,
"member attribute");
}
}

void ExpandMemberAttributeMacros::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity_through,
"member attribute",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed_through,
"member attribute");
}
}

void ExpandSynthesizedMemberMacroRequest::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity,
"member",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed,
"member");
}
}

void ExpandSynthesizedMemberMacroRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity_through,
"member",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed_through,
"member");
}
}

void ExpandPeerMacroRequest::diagnoseCycle(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity,
"peer",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed,
"peer");
}
}

void ExpandPeerMacroRequest::noteCycleStep(DiagnosticEngine &diags) const {
auto decl = std::get<0>(getStorage());
if (auto value = dyn_cast<ValueDecl>(decl)) {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_entity_through,
"peer",
value->getName());
} else {
diags.diagnose(decl->getLoc(),
diag::macro_expand_circular_reference_unnamed_through,
"peer");
}
}
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckDeclPrimary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3796,7 +3796,7 @@ ExpandMacroExpansionDeclRequest::evaluate(Evaluator &evaluator,

// Resolve macro candidates.
auto macro = evaluateOrDefault(
ctx.evaluator, ResolveMacroRequest{MED, dc},
ctx.evaluator, ResolveMacroRequest{MED, MED},
ConcreteDeclRef());
if (!macro)
return None;
Expand Down
6 changes: 4 additions & 2 deletions lib/Sema/TypeCheckMacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ ArrayRef<unsigned> ExpandMemberAttributeMacros::evaluate(Evaluator &evaluator,
return { };

auto *parentDecl = decl->getDeclContext()->getAsDecl();
if (!parentDecl)
if (!parentDecl || !isa<IterableDeclContext>(parentDecl))
return { };

if (isa<PatternBindingDecl>(decl))
Expand Down Expand Up @@ -1478,7 +1478,9 @@ swift::expandConformances(CustomAttr *attr, MacroDecl *macro,
ConcreteDeclRef
ResolveMacroRequest::evaluate(Evaluator &evaluator,
UnresolvedMacroReference macroRef,
DeclContext *dc) const {
const Decl *decl) const {
auto dc = decl->getDeclContext();

// Macro expressions and declarations have their own stored macro
// reference. Use it if it's there.
if (auto *expr = macroRef.getExpr()) {
Expand Down
5 changes: 2 additions & 3 deletions test/Macros/macro_expand_peers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,8 @@ struct S2 {
}

#if TEST_DIAGNOSTICS
// FIXME: Causes reference cycles
// should have error {{cannot find 'nonexistent' in scope}}
// @addCompletionHandlerArbitrarily(nonexistent)
// expected-error@+1 {{cannot find 'nonexistent' in scope}}
@addCompletionHandlerArbitrarily(nonexistent)
func h(a: Int, for b: String, _ value: Double) async -> String {
return b
}
Expand Down