Skip to content

Commit cc062ee

Browse files
committed
Fix precedencegroup and operator decl lookup
Re-implement operator and precedencegroup decl lookup to use `namelookup::getAllImports` and existing decl shadowing logic. This allows us to find operator decls through `@_exported` imports, prefer operator decls defined in the same module over imported decls, and fixes a couple of other subtle issues. Because this new implementation is technically source breaking, as we can find multiple results where we used to only find one result, it's placed behind the new Frontend flag `-enable-new-operator-lookup` (with the aim of enabling it by default when we get a new language mode). However the new logic will always be used if the result is unambiguous. This means that e.g `@_exported` operators will be instantly available as long as there's only one candidate. If multiple candidates are found, we fall back to the old logic. Resolves SR-12132. Resolves rdar://59198796.
1 parent 912baa8 commit cc062ee

24 files changed

+761
-452
lines changed

include/swift/AST/Decl.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7273,12 +7273,6 @@ class InfixOperatorDecl : public OperatorDecl {
72737273

72747274
PrecedenceGroupDecl *getPrecedenceGroup() const;
72757275

7276-
/// True if this decl's attributes conflict with those declared by another
7277-
/// operator.
7278-
bool conflictsWith(InfixOperatorDecl *other) {
7279-
return getPrecedenceGroup() != other->getPrecedenceGroup();
7280-
}
7281-
72827276
static bool classof(const Decl *D) {
72837277
return D->getKind() == DeclKind::InfixOperator;
72847278
}
@@ -7307,12 +7301,6 @@ class PrefixOperatorDecl : public OperatorDecl {
73077301
return { getOperatorLoc(), getNameLoc() };
73087302
}
73097303

7310-
/// True if this decl's attributes conflict with those declared by another
7311-
/// PrefixOperatorDecl.
7312-
bool conflictsWith(PrefixOperatorDecl *other) {
7313-
return false;
7314-
}
7315-
73167304
static bool classof(const Decl *D) {
73177305
return D->getKind() == DeclKind::PrefixOperator;
73187306
}
@@ -7340,12 +7328,6 @@ class PostfixOperatorDecl : public OperatorDecl {
73407328
SourceRange getSourceRange() const {
73417329
return { getOperatorLoc(), getNameLoc() };
73427330
}
7343-
7344-
/// True if this decl's attributes conflict with those declared by another
7345-
/// PostfixOperatorDecl.
7346-
bool conflictsWith(PostfixOperatorDecl *other) {
7347-
return false;
7348-
}
73497331

73507332
static bool classof(const Decl *D) {
73517333
return D->getKind() == DeclKind::PostfixOperator;

include/swift/AST/DeclContext.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,19 @@ namespace swift {
5454
class GenericSignature;
5555
class GenericTypeParamDecl;
5656
class GenericTypeParamType;
57+
class InfixOperatorDecl;
58+
class InfixOperatorLookupResult;
59+
class PrecedenceGroupDecl;
5760
class ProtocolDecl;
5861
class Requirement;
5962
class SourceFile;
6063
class Type;
6164
class ModuleDecl;
6265
class GenericTypeDecl;
6366
class NominalTypeDecl;
67+
class PrecedenceGroupLookupResult;
68+
class PostfixOperatorDecl;
69+
class PrefixOperatorDecl;
6470
class ProtocolConformance;
6571
class ValueDecl;
6672
class Initializer;
@@ -561,6 +567,29 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
561567
ObjCSelector selector,
562568
SmallVectorImpl<AbstractFunctionDecl *> &results) const;
563569

570+
/// Looks up an infix operator with a given \p name.
571+
///
572+
/// This returns a vector of results, as it's possible to find multiple infix
573+
/// operators with different precedence groups.
574+
InfixOperatorLookupResult lookupInfixOperator(Identifier name) const;
575+
576+
/// Looks up an prefix operator with a given \p name.
577+
///
578+
/// If multiple results are found, one is chosen in a stable manner, as
579+
/// prefix operator decls cannot differ other than in name. If no results are
580+
/// found, returns \c nullptr.
581+
PrefixOperatorDecl *lookupPrefixOperator(Identifier name) const;
582+
583+
/// Looks up an postfix operator with a given \p name.
584+
///
585+
/// If multiple results are found, one is chosen in a stable manner, as
586+
/// postfix operator decls cannot differ other than in name. If no results are
587+
/// found, returns \c nullptr.
588+
PostfixOperatorDecl *lookupPostfixOperator(Identifier name) const;
589+
590+
/// Looks up a precedence group with a given \p name.
591+
PrecedenceGroupLookupResult lookupPrecedenceGroup(Identifier name) const;
592+
564593
/// Return the ASTContext for a specified DeclContext by
565594
/// walking up to the enclosing module and returning its ASTContext.
566595
LLVM_READONLY

include/swift/AST/Module.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -592,21 +592,6 @@ class ModuleDecl : public DeclContext, public TypeDecl {
592592
/// FIXME: Remove the integrated REPL.
593593
void clearLookupCache();
594594

595-
/// @{
596-
597-
/// Look up the given operator in this module.
598-
///
599-
/// If the operator is not found, or if there is an ambiguity, returns null.
600-
InfixOperatorDecl *lookupInfixOperator(Identifier name,
601-
SourceLoc diagLoc = {});
602-
PrefixOperatorDecl *lookupPrefixOperator(Identifier name,
603-
SourceLoc diagLoc = {});
604-
PostfixOperatorDecl *lookupPostfixOperator(Identifier name,
605-
SourceLoc diagLoc = {});
606-
PrecedenceGroupDecl *lookupPrecedenceGroup(Identifier name,
607-
SourceLoc diagLoc = {});
608-
/// @}
609-
610595
/// Finds all class members defined in this module.
611596
///
612597
/// This does a simple local lookup, not recursively looking through imports.

include/swift/AST/NameLookupRequests.h

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -594,14 +594,10 @@ class OperatorLookupDescriptor final {
594594
using Storage = llvm::PointerUnion<FileUnit *, ModuleDecl *>;
595595
Storage fileOrModule;
596596
Identifier name;
597-
bool isCascading;
598-
SourceLoc diagLoc;
599597

600598
private:
601-
OperatorLookupDescriptor(Storage fileOrModule, Identifier name,
602-
bool isCascading, SourceLoc diagLoc)
603-
: fileOrModule(fileOrModule), name(name), isCascading(isCascading),
604-
diagLoc(diagLoc) {}
599+
OperatorLookupDescriptor(Storage fileOrModule, Identifier name)
600+
: fileOrModule(fileOrModule), name(name) {}
605601

606602
public:
607603
/// Retrieves the files to perform lookup in.
@@ -613,66 +609,43 @@ class OperatorLookupDescriptor final {
613609
return fileOrModule.dyn_cast<ModuleDecl *>();
614610
}
615611

612+
/// Retrieve the file or module for the lookup, as a DeclContext.
613+
DeclContext *getDC() const {
614+
if (auto *module = getModule())
615+
return module;
616+
return fileOrModule.get<FileUnit *>();
617+
}
618+
616619
friend llvm::hash_code hash_value(const OperatorLookupDescriptor &desc) {
617-
return llvm::hash_combine(desc.fileOrModule, desc.name, desc.isCascading);
620+
return llvm::hash_combine(desc.fileOrModule, desc.name);
618621
}
619622

620623
friend bool operator==(const OperatorLookupDescriptor &lhs,
621624
const OperatorLookupDescriptor &rhs) {
622-
return lhs.fileOrModule == rhs.fileOrModule && lhs.name == rhs.name &&
623-
lhs.isCascading == rhs.isCascading;
625+
return lhs.fileOrModule == rhs.fileOrModule && lhs.name == rhs.name;
624626
}
625627

626628
friend bool operator!=(const OperatorLookupDescriptor &lhs,
627629
const OperatorLookupDescriptor &rhs) {
628630
return !(lhs == rhs);
629631
}
630632

631-
static OperatorLookupDescriptor forFile(FileUnit *file, Identifier name,
632-
bool isCascading, SourceLoc diagLoc) {
633-
return OperatorLookupDescriptor(file, name, isCascading, diagLoc);
633+
static OperatorLookupDescriptor forFile(FileUnit *file, Identifier name) {
634+
return OperatorLookupDescriptor(file, name);
634635
}
635636

636-
static OperatorLookupDescriptor forModule(ModuleDecl *mod, Identifier name,
637-
bool isCascading,
638-
SourceLoc diagLoc) {
639-
return OperatorLookupDescriptor(mod, name, isCascading, diagLoc);
637+
static OperatorLookupDescriptor forModule(ModuleDecl *mod, Identifier name) {
638+
return OperatorLookupDescriptor(mod, name);
640639
}
640+
641+
static OperatorLookupDescriptor forDC(const DeclContext *DC, Identifier name);
641642
};
642643

643644
void simple_display(llvm::raw_ostream &out,
644645
const OperatorLookupDescriptor &desc);
645646

646647
SourceLoc extractNearestSourceLoc(const OperatorLookupDescriptor &desc);
647648

648-
template <typename OperatorType>
649-
class LookupOperatorRequest
650-
: public SimpleRequest<LookupOperatorRequest<OperatorType>,
651-
OperatorType *(OperatorLookupDescriptor),
652-
RequestFlags::Cached> {
653-
using SimpleRequest<LookupOperatorRequest<OperatorType>,
654-
OperatorType *(OperatorLookupDescriptor),
655-
RequestFlags::Cached>::SimpleRequest;
656-
657-
private:
658-
friend SimpleRequest<LookupOperatorRequest<OperatorType>,
659-
OperatorType *(OperatorLookupDescriptor),
660-
RequestFlags::Cached>;
661-
662-
// Evaluation.
663-
OperatorType *evaluate(Evaluator &evaluator,
664-
OperatorLookupDescriptor desc) const;
665-
666-
public:
667-
// Cached.
668-
bool isCached() const { return true; }
669-
};
670-
671-
using LookupPrefixOperatorRequest = LookupOperatorRequest<PrefixOperatorDecl>;
672-
using LookupInfixOperatorRequest = LookupOperatorRequest<InfixOperatorDecl>;
673-
using LookupPostfixOperatorRequest = LookupOperatorRequest<PostfixOperatorDecl>;
674-
using LookupPrecedenceGroupRequest = LookupOperatorRequest<PrecedenceGroupDecl>;
675-
676649
/// Looks up an operator in a given file or module without looking through
677650
/// imports.
678651
class DirectOperatorLookupRequest
@@ -770,6 +743,84 @@ class LookupConformanceInModuleRequest
770743
ProtocolConformanceRef result) const;
771744
};
772745

746+
/// Look up an 'infix operator' decl by name.
747+
class LookupInfixOperatorRequest
748+
: public SimpleRequest<LookupInfixOperatorRequest,
749+
TinyPtrVector<InfixOperatorDecl *>(
750+
OperatorLookupDescriptor),
751+
RequestFlags::Cached> {
752+
public:
753+
using SimpleRequest::SimpleRequest;
754+
755+
private:
756+
friend SimpleRequest;
757+
758+
TinyPtrVector<InfixOperatorDecl *>
759+
evaluate(Evaluator &evaluator, OperatorLookupDescriptor desc) const;
760+
761+
public:
762+
// Cached.
763+
bool isCached() const { return true; }
764+
};
765+
766+
/// Look up an 'prefix operator' decl by name.
767+
class LookupPrefixOperatorRequest
768+
: public SimpleRequest<LookupPrefixOperatorRequest,
769+
PrefixOperatorDecl *(OperatorLookupDescriptor),
770+
RequestFlags::Cached> {
771+
public:
772+
using SimpleRequest::SimpleRequest;
773+
774+
private:
775+
friend SimpleRequest;
776+
777+
PrefixOperatorDecl *evaluate(Evaluator &evaluator,
778+
OperatorLookupDescriptor desc) const;
779+
780+
public:
781+
// Cached.
782+
bool isCached() const { return true; }
783+
};
784+
785+
/// Look up an 'postfix operator' decl by name.
786+
class LookupPostfixOperatorRequest
787+
: public SimpleRequest<LookupPostfixOperatorRequest,
788+
PostfixOperatorDecl *(OperatorLookupDescriptor),
789+
RequestFlags::Cached> {
790+
public:
791+
using SimpleRequest::SimpleRequest;
792+
793+
private:
794+
friend SimpleRequest;
795+
796+
PostfixOperatorDecl *evaluate(Evaluator &evaluator,
797+
OperatorLookupDescriptor desc) const;
798+
799+
public:
800+
// Cached.
801+
bool isCached() const { return true; }
802+
};
803+
804+
/// Look up a precedencegroup decl by name.
805+
class LookupPrecedenceGroupRequest
806+
: public SimpleRequest<LookupPrecedenceGroupRequest,
807+
TinyPtrVector<PrecedenceGroupDecl *>(
808+
OperatorLookupDescriptor),
809+
RequestFlags::Cached> {
810+
public:
811+
using SimpleRequest::SimpleRequest;
812+
813+
private:
814+
friend SimpleRequest;
815+
816+
TinyPtrVector<PrecedenceGroupDecl *>
817+
evaluate(Evaluator &evaluator, OperatorLookupDescriptor descriptor) const;
818+
819+
public:
820+
// Cached.
821+
bool isCached() const { return true; }
822+
};
823+
773824
#define SWIFT_TYPEID_ZONE NameLookup
774825
#define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def"
775826
#include "swift/Basic/DefineTypeIDZone.h"

include/swift/AST/NameLookupTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ SWIFT_REQUEST(NameLookup, LookupPrefixOperatorRequest,
8989
PrefixOperatorDecl *(OperatorLookupDescriptor),
9090
Cached, NoLocationInfo)
9191
SWIFT_REQUEST(NameLookup, LookupInfixOperatorRequest,
92-
InfixOperatorDecl *(OperatorLookupDescriptor),
92+
TinyPtrVector<InfixOperatorDecl *>(OperatorLookupDescriptor),
9393
Cached, NoLocationInfo)
9494
SWIFT_REQUEST(NameLookup, LookupPostfixOperatorRequest,
9595
PostfixOperatorDecl *(OperatorLookupDescriptor),
9696
Cached, NoLocationInfo)
9797
SWIFT_REQUEST(NameLookup, LookupPrecedenceGroupRequest,
98-
PrecedenceGroupDecl *(OperatorLookupDescriptor),
98+
TinyPtrVector<PrecedenceGroupDecl *>(OperatorLookupDescriptor),
9999
Cached, NoLocationInfo)

0 commit comments

Comments
 (0)