Skip to content

Commit 65f8d5b

Browse files
committed
Ensure that macro-provided operators can be found by witness lookup
When looking for an operator to satisfy a protocol requirement, we currently depend on global operator lookup for everything except local types. However, macro-provided operators aren't found by global operator lookup, so perform a member lookup for such cases in addition to global operator lookup. This makes macro-provided operators visible through protocol requirements they witness. (cherry picked from commit b7b6a1d)
1 parent a82ca01 commit 65f8d5b

File tree

2 files changed

+58
-7
lines changed

2 files changed

+58
-7
lines changed

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/macro_expand.swift

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,42 @@ struct HasEqualsSelf3 {
464464
struct HasEqualsSelf4 {
465465
}
466466

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+
467487
func testHasEqualsSelf(
468-
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4
488+
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4,
489+
xP: HasEqualsSelfP, yP: HasEqualsSelf2P, zP: HasEqualsSelf3P,
490+
wP: HasEqualsSelf4P
469491
) {
470492
#if TEST_DIAGNOSTICS
471493
// Global operator lookup doesn't find member operators introduced by macros.
472-
_ = (x == true) // expected-error{{cannot convert value of type}}
473-
_ = (y == true) // expected-error{{cannot convert value of type}}
474-
_ = (z == true) // expected-error{{cannot convert value of type}}
475-
_ = (w == true) // expected-error{{cannot convert value of type}}
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 '=='}}
476498
#endif
499+
500+
// These should be found through the protocol.
501+
_ = (xP == true)
502+
_ = (yP == true)
503+
_ = (zP == true)
504+
_ = (wP == true)
477505
}

0 commit comments

Comments
 (0)