Files
swift-mirror/include/swift/AST/OperatorNameLookup.h
Hamish Knight cc062ee2bb 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.
2020-05-18 14:33:43 -07:00

128 lines
4.4 KiB
C++

//===--- OperatorNameLookup.h - Operator and Precedence Lookup --*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2020 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines interfaces for looking up operator and precedence group
// declarations.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_AST_OPERATOR_NAME_LOOKUP_H
#define SWIFT_AST_OPERATOR_NAME_LOOKUP_H
#include "swift/AST/Identifier.h"
#include "swift/AST/Module.h"
#include "llvm/ADT/TinyPtrVector.h"
namespace swift {
/// Base class for infix operator and precedence group lookup results.
template <typename Derived, typename DeclTy>
class OperatorLookupResultBase {
protected:
const DeclContext *ModuleDC;
Identifier Name;
TinyPtrVector<DeclTy *> Results;
private:
const Derived &asDerived() const {
return *static_cast<const Derived *>(this);
}
public:
OperatorLookupResultBase(const DeclContext *moduleDC, Identifier name,
TinyPtrVector<DeclTy *> &&results)
: ModuleDC(moduleDC), Name(name), Results(std::move(results)) {}
/// Retrieve the underlying results vector.
TinyPtrVector<DeclTy *> get() && { return std::move(Results); }
/// If the lookup produced a single result, returns it. Otherwise returns
/// \c nullptr.
DeclTy *getSingle() const {
return Results.size() == 1 ? Results[0] : nullptr;
}
/// If the lookup produced a single result, returns it. Otherwise, emits an
/// ambiguity or missing decl diagnostic, and returns \c nullptr.
DeclTy *getSingleOrDiagnose(SourceLoc loc, bool forBuiltin = false) const {
if (auto single = getSingle())
return single;
if (isAmbiguous()) {
asDerived().diagnoseAmbiguity(loc);
} else {
assert(!hasResults());
asDerived().diagnoseMissing(loc, forBuiltin);
}
return nullptr;
}
using const_iterator = typename decltype(Results)::const_iterator;
const_iterator begin() const { return Results.begin(); }
const_iterator end() const { return Results.end(); }
/// Whether the lookup produced at least one result.
bool hasResults() const { return !Results.empty(); }
/// Whether the lookup produced multiple ambiguous results.
bool isAmbiguous() const { return Results.size() > 1; }
friend bool operator==(const OperatorLookupResultBase &lhs,
const OperatorLookupResultBase &rhs) {
return lhs.Results == rhs.Results;
}
friend bool operator!=(const OperatorLookupResultBase &lhs,
const OperatorLookupResultBase &rhs) {
return !(lhs == rhs);
}
friend void simple_display(llvm::raw_ostream &out,
const OperatorLookupResultBase &result) {
simple_display(out, result.Results);
}
};
/// The result of a precedence group lookup.
class PrecedenceGroupLookupResult final
: public OperatorLookupResultBase<PrecedenceGroupLookupResult,
PrecedenceGroupDecl> {
friend class OperatorLookupResultBase<PrecedenceGroupLookupResult,
PrecedenceGroupDecl>;
public:
PrecedenceGroupLookupResult(const DeclContext *moduleDC, Identifier name,
TinyPtrVector<PrecedenceGroupDecl *> &&results)
: OperatorLookupResultBase(moduleDC, name, std::move(results)) {}
void diagnoseAmbiguity(SourceLoc loc) const;
void diagnoseMissing(SourceLoc loc, bool forBuiltin) const;
};
/// The result of an infix operator lookup.
class InfixOperatorLookupResult final
: public OperatorLookupResultBase<InfixOperatorLookupResult,
InfixOperatorDecl> {
friend class OperatorLookupResultBase<InfixOperatorLookupResult,
InfixOperatorDecl>;
public:
InfixOperatorLookupResult(const DeclContext *moduleDC, Identifier name,
TinyPtrVector<InfixOperatorDecl *> &&results)
: OperatorLookupResultBase(moduleDC, name, std::move(results)) {}
void diagnoseAmbiguity(SourceLoc loc) const;
void diagnoseMissing(SourceLoc loc, bool forBuiltin) const;
};
} // end namespace swift
#endif