Skip to content

Commit b7b6a1d

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.
1 parent 343947a commit b7b6a1d

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"
@@ -1318,6 +1320,25 @@ WitnessChecker::lookupValueWitnessesViaImplementsAttr(
13181320
removeShadowedDecls(witnesses, DC);
13191321
}
13201322

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

13431366
if (doUnqualifiedLookup) {
13441367
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
@@ -465,14 +465,42 @@ struct HasEqualsSelf3 {
465465
struct HasEqualsSelf4 {
466466
}
467467

468+
protocol SelfEqualsBoolProto { // expected-note 4{{where 'Self' =}}
469+
static func ==(lhs: Self, rhs: Bool) -> Bool
470+
}
471+
472+
struct HasEqualsSelfP: SelfEqualsBoolProto {
473+
#addSelfEqualsOperator
474+
}
475+
476+
struct HasEqualsSelf2P: SelfEqualsBoolProto {
477+
#addSelfEqualsOperatorArbitrary
478+
}
479+
480+
@AddSelfEqualsMemberOperator
481+
struct HasEqualsSelf3P: SelfEqualsBoolProto {
482+
}
483+
484+
@AddSelfEqualsMemberOperatorArbitrary
485+
struct HasEqualsSelf4P: SelfEqualsBoolProto {
486+
}
487+
468488
func testHasEqualsSelf(
469-
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4
489+
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4,
490+
xP: HasEqualsSelfP, yP: HasEqualsSelf2P, zP: HasEqualsSelf3P,
491+
wP: HasEqualsSelf4P
470492
) {
471493
#if TEST_DIAGNOSTICS
472494
// Global operator lookup doesn't find member operators introduced by macros.
473-
_ = (x == true) // expected-error{{cannot convert value of type}}
474-
_ = (y == true) // expected-error{{cannot convert value of type}}
475-
_ = (z == true) // expected-error{{cannot convert value of type}}
476-
_ = (w == true) // expected-error{{cannot convert value of type}}
495+
_ = (x == true) // expected-error{{referencing operator function '=='}}
496+
_ = (y == true) // expected-error{{referencing operator function '=='}}
497+
_ = (z == true) // expected-error{{referencing operator function '=='}}
498+
_ = (w == true) // expected-error{{referencing operator function '=='}}
477499
#endif
500+
501+
// These should be found through the protocol.
502+
_ = (xP == true)
503+
_ = (yP == true)
504+
_ = (zP == true)
505+
_ = (wP == true)
478506
}

0 commit comments

Comments
 (0)