Skip to content

Commit 7203d52

Browse files
authored
Merge pull request #66325 from DougGregor/macro-operators-without-global-operator-lookup-5.9
2 parents 22bdcb2 + 65f8d5b commit 7203d52

File tree

5 files changed

+187
-6
lines changed

5 files changed

+187
-6
lines changed

lib/AST/Module.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ void SourceLookupCache::addToUnqualifiedLookupCache(Range decls,
249249
// Cache the value under both its compound name and its full name.
250250
TopLevelValues.add(VD);
251251

252-
if (VD->getAttrs().hasAttribute<CustomAttr>()) {
252+
if (!onlyOperators && VD->getAttrs().hasAttribute<CustomAttr>()) {
253253
MayHaveAuxiliaryDecls.push_back(VD);
254254
}
255255
}
@@ -279,8 +279,10 @@ void SourceLookupCache::addToUnqualifiedLookupCache(Range decls,
279279
else if (auto *PG = dyn_cast<PrecedenceGroupDecl>(D))
280280
PrecedenceGroups[PG->getName()].push_back(PG);
281281

282-
else if (auto *MED = dyn_cast<MacroExpansionDecl>(D))
283-
MayHaveAuxiliaryDecls.push_back(MED);
282+
else if (auto *MED = dyn_cast<MacroExpansionDecl>(D)) {
283+
if (!onlyOperators)
284+
MayHaveAuxiliaryDecls.push_back(MED);
285+
}
284286
}
285287
}
286288

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
#include "swift/AST/GenericEnvironment.h"
3636
#include "swift/AST/GenericSignature.h"
3737
#include "swift/AST/NameLookup.h"
38+
#include "swift/AST/NameLookupRequests.h"
3839
#include "swift/AST/ParameterList.h"
3940
#include "swift/AST/PrettyStackTrace.h"
41+
#include "swift/AST/PotentialMacroExpansions.h"
4042
#include "swift/AST/ProtocolConformance.h"
4143
#include "swift/AST/TypeCheckRequests.h"
4244
#include "swift/AST/TypeDeclFinder.h"
@@ -1314,6 +1316,25 @@ WitnessChecker::lookupValueWitnessesViaImplementsAttr(
13141316
removeShadowedDecls(witnesses, DC);
13151317
}
13161318

1319+
/// Determine whether the given context may expand an operator with the given name.
1320+
static bool contextMayExpandOperator(
1321+
DeclContext *dc, DeclBaseName operatorName
1322+
) {
1323+
TypeOrExtensionDecl decl;
1324+
if (auto nominal = dyn_cast<NominalTypeDecl>(dc))
1325+
decl = nominal;
1326+
else if (auto ext = dyn_cast<ExtensionDecl>(dc))
1327+
decl = ext;
1328+
else
1329+
return false;
1330+
1331+
ASTContext &ctx = dc->getASTContext();
1332+
auto potentialExpansions = evaluateOrDefault(
1333+
ctx.evaluator, PotentialMacroExpansionsInContextRequest{decl},
1334+
PotentialMacroExpansions());
1335+
return potentialExpansions.shouldExpandForName(operatorName);
1336+
}
1337+
13171338
SmallVector<ValueDecl *, 4>
13181339
WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) {
13191340
assert(!isa<AssociatedTypeDecl>(req) && "Not for lookup for type witnesses*");
@@ -1331,10 +1352,12 @@ WitnessChecker::lookupValueWitnesses(ValueDecl *req, bool *ignoringNames) {
13311352
// An operator function is the only kind of witness that requires global
13321353
// lookup. However, because global lookup doesn't enter local contexts,
13331354
// an additional, qualified lookup is warranted when the conforming type
1334-
// is declared in a local context.
1355+
// is declared in a local context or when the operator could come from a
1356+
// macro expansion.
13351357
const bool doUnqualifiedLookup = req->isOperator();
13361358
const bool doQualifiedLookup =
1337-
!req->isOperator() || DC->getParent()->getLocalContext();
1359+
!req->isOperator() || DC->getParent()->getLocalContext() ||
1360+
contextMayExpandOperator(DC, req->getName().getBaseName());
13381361

13391362
if (doUnqualifiedLookup) {
13401363
auto lookup = TypeChecker::lookupUnqualified(DC->getModuleScopeContext(),

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,3 +1505,63 @@ public struct SingleMemberMacro: MemberMacro {
15051505
]
15061506
}
15071507
}
1508+
1509+
public struct UseIdentifierMacro: DeclarationMacro {
1510+
public static func expansion(
1511+
of node: some FreestandingMacroExpansionSyntax,
1512+
in context: some MacroExpansionContext
1513+
) throws -> [DeclSyntax] {
1514+
guard let argument = node.argumentList.first?.expression.as(StringLiteralExprSyntax.self) else {
1515+
fatalError("boom")
1516+
}
1517+
return [
1518+
"""
1519+
func \(context.makeUniqueName("name"))() {
1520+
_ = \(raw: argument.segments.first!)
1521+
}
1522+
""",
1523+
"""
1524+
struct Foo {
1525+
var \(context.makeUniqueName("name")): Int {
1526+
_ = \(raw: argument.segments.first!)
1527+
return 0
1528+
}
1529+
}
1530+
"""
1531+
]
1532+
}
1533+
}
1534+
1535+
public struct StaticFooFuncMacro: DeclarationMacro {
1536+
public static func expansion(
1537+
of node: some FreestandingMacroExpansionSyntax,
1538+
in context: some MacroExpansionContext
1539+
) throws -> [DeclSyntax] {
1540+
return [
1541+
"static func foo() {}",
1542+
]
1543+
}
1544+
}
1545+
1546+
public struct SelfAlwaysEqualOperator: DeclarationMacro {
1547+
public static func expansion(
1548+
of node: some FreestandingMacroExpansionSyntax,
1549+
in context: some MacroExpansionContext
1550+
) throws -> [DeclSyntax] {
1551+
return [
1552+
"static func ==(lhs: Self, rhs: Bool) -> Bool { true }",
1553+
]
1554+
}
1555+
}
1556+
1557+
extension SelfAlwaysEqualOperator: MemberMacro {
1558+
public static func expansion(
1559+
of node: AttributeSyntax,
1560+
providingMembersOf decl: some DeclGroupSyntax,
1561+
in context: some MacroExpansionContext
1562+
) throws -> [DeclSyntax] {
1563+
return [
1564+
"static func ==(lhs: Self, rhs: Bool) -> Bool { true }",
1565+
]
1566+
}
1567+
}

test/Macros/macro_expand.swift

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
// RUN: %target-swift-frontend -swift-version 5 -emit-ir -load-plugin-library %t/%target-library-name(MacroDefinition) %s -module-name MacroUser -o - -g | %FileCheck --check-prefix CHECK-IR %s
2525

2626
// Execution testing
27-
// RUN: %target-build-swift -swift-version 5 -g -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser
27+
// RUN: %target-build-swift -swift-version 5 -g -load-plugin-library %t/%target-library-name(MacroDefinition) %s -o %t/main -module-name MacroUser -Xfrontend -emit-dependencies-path -Xfrontend %t/main.d -Xfrontend -emit-reference-dependencies-path -Xfrontend %t/main.swiftdeps
2828
// RUN: %target-codesign %t/main
2929
// RUN: %target-run %t/main | %FileCheck %s
3030

@@ -417,3 +417,89 @@ func testFreestandingClosureNesting() {
417417
func testLocalVarsFromDeclarationMacros() {
418418
#varValue
419419
}
420+
421+
// Variadic macro
422+
@freestanding(declaration, names: arbitrary) macro emptyDecl(_: String...) = #externalMacro(module: "MacroDefinition", type: "EmptyDeclarationMacro")
423+
424+
struct TakesVariadic {
425+
#emptyDecl("foo", "bar")
426+
}
427+
428+
// Funkiness with static functions introduced via macro expansions.
429+
@freestanding(declaration, names: named(foo())) public macro staticFooFunc() = #externalMacro(module: "MacroDefinition", type: "StaticFooFuncMacro")
430+
@freestanding(declaration, names: arbitrary) public macro staticFooFuncArbitrary() = #externalMacro(module: "MacroDefinition", type: "StaticFooFuncMacro")
431+
432+
class HasAnExpandedStatic {
433+
#staticFooFunc()
434+
}
435+
436+
class HasAnExpandedStatic2 {
437+
#staticFooFuncArbitrary()
438+
}
439+
440+
func testHasAnExpandedStatic() {
441+
#if TEST_DIAGNOSTICS
442+
foo() // expected-error{{cannot find 'foo' in scope}}
443+
#endif
444+
}
445+
446+
@freestanding(declaration, names: named(==)) public macro addSelfEqualsOperator() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
447+
@freestanding(declaration, names: arbitrary) public macro addSelfEqualsOperatorArbitrary() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
448+
@attached(member, names: named(==)) public macro AddSelfEqualsMemberOperator() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
449+
@attached(member, names: arbitrary) public macro AddSelfEqualsMemberOperatorArbitrary() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
450+
451+
struct HasEqualsSelf {
452+
#addSelfEqualsOperator
453+
}
454+
455+
struct HasEqualsSelf2 {
456+
#addSelfEqualsOperatorArbitrary
457+
}
458+
459+
@AddSelfEqualsMemberOperator
460+
struct HasEqualsSelf3 {
461+
}
462+
463+
@AddSelfEqualsMemberOperatorArbitrary
464+
struct HasEqualsSelf4 {
465+
}
466+
467+
protocol SelfEqualsBoolProto { // expected-note 4{{where 'Self' =}}
468+
static func ==(lhs: Self, rhs: Bool) -> Bool
469+
}
470+
471+
struct HasEqualsSelfP: SelfEqualsBoolProto {
472+
#addSelfEqualsOperator
473+
}
474+
475+
struct HasEqualsSelf2P: SelfEqualsBoolProto {
476+
#addSelfEqualsOperatorArbitrary
477+
}
478+
479+
@AddSelfEqualsMemberOperator
480+
struct HasEqualsSelf3P: SelfEqualsBoolProto {
481+
}
482+
483+
@AddSelfEqualsMemberOperatorArbitrary
484+
struct HasEqualsSelf4P: SelfEqualsBoolProto {
485+
}
486+
487+
func testHasEqualsSelf(
488+
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4,
489+
xP: HasEqualsSelfP, yP: HasEqualsSelf2P, zP: HasEqualsSelf3P,
490+
wP: HasEqualsSelf4P
491+
) {
492+
#if TEST_DIAGNOSTICS
493+
// Global operator lookup doesn't find member operators introduced by macros.
494+
_ = (x == true) // expected-error{{referencing operator function '=='}}
495+
_ = (y == true) // expected-error{{referencing operator function '=='}}
496+
_ = (z == true) // expected-error{{referencing operator function '=='}}
497+
_ = (w == true) // expected-error{{referencing operator function '=='}}
498+
#endif
499+
500+
// These should be found through the protocol.
501+
_ = (xP == true)
502+
_ = (yP == true)
503+
_ = (zP == true)
504+
_ = (wP == true)
505+
}

test/Macros/macro_expand_primary.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,13 @@ final class Dog: Observable {
8585
func test() {
8686
observeDog()
8787
}
88+
89+
90+
@freestanding(declaration, names: named(Foo)) macro useIdentifier(_ value: String) = #externalMacro(module: "MacroDefinition", type: "UseIdentifierMacro")
91+
92+
#if false
93+
#useIdentifier("totallyNotDefined")
94+
#else
95+
let hello = "Hello"
96+
#useIdentifier("hello")
97+
#endif

0 commit comments

Comments
 (0)