mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #31506 from hamishknight/hello-operator
This commit is contained in:
@@ -1050,72 +1050,6 @@ LookupConformanceInModuleRequest::evaluate(
|
||||
return ProtocolConformanceRef(conformance);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
struct OperatorLookup {
|
||||
// Don't fold this into the static_assert: this would trigger an MSVC bug
|
||||
// that causes the assertion to fail.
|
||||
static constexpr T* ptr = static_cast<T*>(nullptr);
|
||||
static_assert(ptr, "Only usable with operators");
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperatorLookup<PrefixOperatorDecl> {
|
||||
static PrefixOperatorDecl *lookup(Evaluator &eval,
|
||||
const OperatorLookupDescriptor &desc) {
|
||||
// We can return the first prefix operator. All prefix operators of the
|
||||
// same name are equivalent.
|
||||
DirectOperatorLookupRequest req{desc, OperatorFixity::Prefix};
|
||||
auto results = evaluateOrDefault(eval, req, {});
|
||||
return results.empty() ? nullptr : cast<PrefixOperatorDecl>(results[0]);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperatorLookup<InfixOperatorDecl> {
|
||||
static InfixOperatorDecl *lookup(Evaluator &eval,
|
||||
const OperatorLookupDescriptor &desc) {
|
||||
// Return the first result if it exists.
|
||||
DirectOperatorLookupRequest req{desc, OperatorFixity::Infix};
|
||||
auto results = evaluateOrDefault(eval, req, {});
|
||||
return results.empty() ? nullptr : cast<InfixOperatorDecl>(results[0]);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperatorLookup<PostfixOperatorDecl> {
|
||||
static PostfixOperatorDecl *lookup(Evaluator &eval,
|
||||
const OperatorLookupDescriptor &desc) {
|
||||
// We can return the first postfix operator. All postfix operators of the
|
||||
// same name are equivalent.
|
||||
DirectOperatorLookupRequest req{desc, OperatorFixity::Postfix};
|
||||
auto results = evaluateOrDefault(eval, req, {});
|
||||
return results.empty() ? nullptr : cast<PostfixOperatorDecl>(results[0]);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OperatorLookup<PrecedenceGroupDecl> {
|
||||
static PrecedenceGroupDecl *lookup(Evaluator &eval,
|
||||
const OperatorLookupDescriptor &desc) {
|
||||
// Return the first result if it exists.
|
||||
auto results =
|
||||
evaluateOrDefault(eval, DirectPrecedenceGroupLookupRequest{desc}, {});
|
||||
return results.empty() ? nullptr : results[0];
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
/// A helper class to sneak around C++ access control rules.
|
||||
class SourceFile::Impl {
|
||||
public:
|
||||
/// Only intended for use by lookupOperatorDeclForName.
|
||||
static ArrayRef<SourceFile::ImportedModuleDesc>
|
||||
getImportsForSourceFile(const SourceFile &SF) {
|
||||
return *SF.Imports;
|
||||
}
|
||||
};
|
||||
|
||||
struct SourceFile::SourceFileSyntaxInfo {
|
||||
const bool Enable;
|
||||
/// The root of the syntax tree representing the source file.
|
||||
@@ -1136,180 +1070,6 @@ void SourceFile::setSyntaxRoot(syntax::SourceFileSyntax &&Root) {
|
||||
SyntaxInfo->SyntaxRoot.emplace(Root);
|
||||
}
|
||||
|
||||
template<typename OP_DECL>
|
||||
static Optional<OP_DECL *>
|
||||
lookupOperatorDeclForName(ModuleDecl *M, SourceLoc Loc, Identifier Name,
|
||||
bool isCascading);
|
||||
|
||||
template<typename OP_DECL>
|
||||
using ImportedOperatorsMap = llvm::SmallDenseMap<OP_DECL*, bool, 16>;
|
||||
|
||||
template<typename OP_DECL>
|
||||
static typename ImportedOperatorsMap<OP_DECL>::iterator
|
||||
checkOperatorConflicts(const SourceFile &SF, SourceLoc loc,
|
||||
ImportedOperatorsMap<OP_DECL> &importedOperators) {
|
||||
// Check for conflicts.
|
||||
auto i = importedOperators.begin(), end = importedOperators.end();
|
||||
auto start = i;
|
||||
for (++i; i != end; ++i) {
|
||||
if (i->first->conflictsWith(start->first)) {
|
||||
if (loc.isValid()) {
|
||||
ASTContext &C = SF.getASTContext();
|
||||
C.Diags.diagnose(loc, diag::ambiguous_operator_decls);
|
||||
start->first->diagnose(diag::found_this_operator_decl);
|
||||
i->first->diagnose(diag::found_this_operator_decl);
|
||||
}
|
||||
return end;
|
||||
}
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
template<>
|
||||
typename ImportedOperatorsMap<PrecedenceGroupDecl>::iterator
|
||||
checkOperatorConflicts(const SourceFile &SF, SourceLoc loc,
|
||||
ImportedOperatorsMap<PrecedenceGroupDecl> &importedGroups) {
|
||||
if (importedGroups.size() == 1)
|
||||
return importedGroups.begin();
|
||||
|
||||
// Any sort of ambiguity is an error.
|
||||
if (loc.isValid()) {
|
||||
ASTContext &C = SF.getASTContext();
|
||||
C.Diags.diagnose(loc, diag::ambiguous_precedence_groups);
|
||||
for (auto &entry : importedGroups) {
|
||||
entry.first->diagnose(diag::found_this_precedence_group);
|
||||
}
|
||||
}
|
||||
return importedGroups.end();
|
||||
}
|
||||
|
||||
// Returns None on error, Optional(nullptr) if no operator decl found, or
|
||||
// Optional(decl) if decl was found.
|
||||
template <typename OP_DECL>
|
||||
static Optional<OP_DECL *>
|
||||
lookupOperatorDeclForName(const FileUnit &File, SourceLoc Loc,
|
||||
Identifier Name, bool includePrivate,
|
||||
bool isCascading) {
|
||||
auto &eval = File.getASTContext().evaluator;
|
||||
auto desc = OperatorLookupDescriptor::forFile(const_cast<FileUnit *>(&File),
|
||||
Name, isCascading,
|
||||
/*diagLoc*/ SourceLoc());
|
||||
switch (File.getKind()) {
|
||||
case FileUnitKind::Builtin:
|
||||
// The Builtin module declares no operators.
|
||||
return nullptr;
|
||||
case FileUnitKind::Synthesized:
|
||||
// Synthesized files currently declare no operators.
|
||||
return nullptr;
|
||||
case FileUnitKind::Source:
|
||||
break;
|
||||
case FileUnitKind::SerializedAST:
|
||||
case FileUnitKind::ClangModule:
|
||||
case FileUnitKind::DWARFModule:
|
||||
return OperatorLookup<OP_DECL>::lookup(eval, desc);
|
||||
}
|
||||
|
||||
auto &SF = cast<SourceFile>(File);
|
||||
assert(SF.ASTStage >= SourceFile::ImportsResolved);
|
||||
|
||||
// Check if the decl exists on the file.
|
||||
if (auto *op = OperatorLookup<OP_DECL>::lookup(eval, desc))
|
||||
return op;
|
||||
|
||||
// Look for imported operator decls.
|
||||
// Record whether they come from re-exported modules.
|
||||
// FIXME: We ought to prefer operators elsewhere in this module before we
|
||||
// check imports.
|
||||
auto ownModule = SF.getParentModule();
|
||||
ImportedOperatorsMap<OP_DECL> importedOperators;
|
||||
for (auto &imported : SourceFile::Impl::getImportsForSourceFile(SF)) {
|
||||
// Protect against source files that contrive to import their own modules.
|
||||
if (imported.module.importedModule == ownModule)
|
||||
continue;
|
||||
|
||||
bool isExported =
|
||||
imported.importOptions.contains(SourceFile::ImportFlags::Exported);
|
||||
if (!includePrivate && !isExported)
|
||||
continue;
|
||||
|
||||
Optional<OP_DECL *> maybeOp = lookupOperatorDeclForName<OP_DECL>(
|
||||
imported.module.importedModule, Loc, Name, isCascading);
|
||||
if (!maybeOp)
|
||||
return None;
|
||||
|
||||
if (OP_DECL *op = *maybeOp)
|
||||
importedOperators[op] |= isExported;
|
||||
}
|
||||
|
||||
llvm::PointerIntPair<OP_DECL *, 1, /*isPrivate*/ bool> result = {nullptr,
|
||||
true};
|
||||
|
||||
if (!importedOperators.empty()) {
|
||||
auto start = checkOperatorConflicts(SF, Loc, importedOperators);
|
||||
if (start == importedOperators.end())
|
||||
return None;
|
||||
result = { start->first, start->second };
|
||||
}
|
||||
|
||||
if (includePrivate || result.getInt())
|
||||
return result.getPointer();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename OP_DECL>
|
||||
static Optional<OP_DECL *>
|
||||
lookupOperatorDeclForName(ModuleDecl *M, SourceLoc Loc, Identifier Name,
|
||||
bool isCascading) {
|
||||
OP_DECL *result = nullptr;
|
||||
for (const FileUnit *File : M->getFiles()) {
|
||||
auto next = lookupOperatorDeclForName<OP_DECL>(*File, Loc, Name, false,
|
||||
isCascading);
|
||||
if (!next.hasValue())
|
||||
return next;
|
||||
|
||||
// FIXME: Diagnose ambiguity.
|
||||
if (*next && result)
|
||||
return None;
|
||||
if (*next)
|
||||
result = *next;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename OperatorType>
|
||||
OperatorType *LookupOperatorRequest<OperatorType>::evaluate(
|
||||
Evaluator &evaluator, OperatorLookupDescriptor desc) const {
|
||||
auto *file = desc.fileOrModule.get<FileUnit *>();
|
||||
auto result =
|
||||
lookupOperatorDeclForName<OperatorType>(*file, desc.diagLoc, desc.name,
|
||||
/*includePrivate*/ true,
|
||||
desc.isCascading);
|
||||
if (!result.hasValue())
|
||||
return nullptr;
|
||||
|
||||
if (!result.getValue()) {
|
||||
result = lookupOperatorDeclForName<OperatorType>(file->getParentModule(),
|
||||
desc.diagLoc, desc.name,
|
||||
desc.isCascading);
|
||||
}
|
||||
return result.hasValue() ? result.getValue() : nullptr;
|
||||
}
|
||||
|
||||
#define LOOKUP_OPERATOR(Kind) \
|
||||
Kind##Decl *ModuleDecl::lookup##Kind(Identifier name, SourceLoc loc) { \
|
||||
auto result = lookupOperatorDeclForName<Kind##Decl>( \
|
||||
this, loc, name, /*isCascading*/ false); \
|
||||
return result ? *result : nullptr; \
|
||||
} \
|
||||
template Kind##Decl *LookupOperatorRequest<Kind##Decl>::evaluate( \
|
||||
Evaluator &e, OperatorLookupDescriptor) const;
|
||||
|
||||
LOOKUP_OPERATOR(PrefixOperator)
|
||||
LOOKUP_OPERATOR(InfixOperator)
|
||||
LOOKUP_OPERATOR(PostfixOperator)
|
||||
LOOKUP_OPERATOR(PrecedenceGroup)
|
||||
#undef LOOKUP_OPERATOR
|
||||
|
||||
void DirectOperatorLookupRequest::writeDependencySink(
|
||||
evaluator::DependencyCollector &reqTracker,
|
||||
TinyPtrVector<OperatorDecl *> ops) const {
|
||||
|
||||
Reference in New Issue
Block a user