Skip to content

Commit d12eae4

Browse files
authored
Merge pull request swiftlang#66320 from DougGregor/macro-operators-without-global-operator-lookup
Eliminate macro-generated operators from global operator lookup
2 parents 7c83991 + b7b6a1d commit d12eae4

File tree

3 files changed

+64
-28
lines changed

3 files changed

+64
-28
lines changed

lib/AST/Module.cpp

Lines changed: 5 additions & 16 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

@@ -403,13 +405,6 @@ void SourceLookupCache::populateAuxiliaryDeclCache() {
403405
for (auto macroNames : introducedNames) {
404406
auto macroRef = macroNames.getFirst();
405407
for (auto name : macroNames.getSecond()) {
406-
407-
// If this macro isn't in a module-scope context, and the introduced
408-
// name isn't an operator, we shouldn't be able to see it.
409-
if (!decl->getDeclContext()->isModuleScopeContext() &&
410-
!name.getBaseName().isOperator())
411-
continue;
412-
413408
auto *placeholder = MissingDecl::forUnexpandedMacro(macroRef, decl);
414409
name.addToLookupTable(TopLevelAuxiliaryDecls, placeholder);
415410
}
@@ -492,12 +487,6 @@ void SourceLookupCache::lookupValue(DeclName Name, NLKind LookupKind,
492487
for (auto *unexpandedDecl : unexpandedDecls) {
493488
unexpandedDecl->forEachMacroExpandedDecl(
494489
[&](ValueDecl *decl) {
495-
// If the declaration is not a module-scope declaration, and
496-
// isn't an operator, ignore it.
497-
if (!decl->getDeclContext()->isModuleScopeContext() &&
498-
!decl->getName().getBaseName().isOperator())
499-
return;
500-
501490
if (decl->getName().matchesRef(Name)) {
502491
if (macroExpandedDecls.insert(decl).second)
503492
Result.push_back(decl);

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

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

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

test/Macros/macro_expand.swift

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -465,18 +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
) {
471-
_ = (x == true)
472-
_ = (y == true)
473493
#if TEST_DIAGNOSTICS
474-
// FIXME: This is technically a bug, because we should be able to find the
475-
// == operator introduced through a member operator. However, we might
476-
// want to change the rule rather than implement this.
477-
_ = (z == true) // expected-error{{binary operator '==' cannot be applied to operands}}
478-
// expected-note@-1{{overloads for '==' exist with these partially matching parameter lists}}
479-
_ = (w == true) // expected-error{{binary operator '==' cannot be applied to operands}}
480-
// expected-note@-1{{overloads for '==' exist with these partially matching parameter lists}}
494+
// Global operator lookup doesn't find member operators introduced by macros.
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 '=='}}
481499
#endif
500+
501+
// These should be found through the protocol.
502+
_ = (xP == true)
503+
_ = (yP == true)
504+
_ = (zP == true)
505+
_ = (wP == true)
482506
}

0 commit comments

Comments
 (0)