Skip to content

Import member operator functions as static members #32293

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 84 additions & 7 deletions include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,15 +179,26 @@ class AbstractionPattern {
/// type. ObjCMethod is valid. OtherData is an encoded foreign
/// error index.
ObjCMethodType,
/// The uncurried imported type of a C++ method. OrigType is valid and is a
/// function type. CXXMethod is valid.
/// The uncurried imported type of a C++ non-operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CXXMethodType,
/// The curried imported type of a C++ method. OrigType is valid and is a
/// function type. CXXMethod is valid.
/// The curried imported type of a C++ non-operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CurriedCXXMethodType,
/// The partially-applied curried imported type of a C++ method. OrigType is
/// valid and is a function type. CXXMethod is valid.
/// The partially-applied curried imported type of a C++ non-operator
/// non-static member function. OrigType is valid and is a function type.
/// CXXMethod is valid.
PartialCurriedCXXMethodType,
/// The uncurried imported type of a C++ operator non-static member
/// function. OrigType is valid and is a function type. CXXMethod is valid.
CXXOperatorMethodType,
/// The curried imported type of a C++ operator non-static member function.
/// OrigType is valid and is a function type. CXXMethod is valid.
CurriedCXXOperatorMethodType,
/// The partially-applied curried imported type of a C++ operator non-static
/// member function. OrigType is valid and is a function type. CXXMethod is
/// valid.
PartialCurriedCXXOperatorMethodType,
/// A Swift function whose parameters and results are opaque. This is
/// like `AP::Type<T>((T) -> T)`, except that the number of parameters is
/// unspecified.
Expand Down Expand Up @@ -341,6 +352,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
return true;

default:
Expand Down Expand Up @@ -465,6 +479,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
return true;
case Kind::Invalid:
case Kind::Opaque:
Expand Down Expand Up @@ -541,6 +558,10 @@ class AbstractionPattern {
static AbstractionPattern
getCurriedCXXMethod(CanType origType, const AbstractFunctionDecl *function);

static AbstractionPattern
getCurriedCXXOperatorMethod(CanType origType,
const AbstractFunctionDecl *function);

/// Return an abstraction pattern for the uncurried type of a C++ method.
///
/// For example, if the original function is:
Expand All @@ -556,6 +577,15 @@ class AbstractionPattern {
return pattern;
}

static AbstractionPattern
getCXXOperatorMethod(CanType origType, const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method,
Kind::CXXOperatorMethodType);
return pattern;
}

/// Return an abstraction pattern for the curried type of a C++ method.
///
/// For example, if the original function is:
Expand All @@ -572,6 +602,16 @@ class AbstractionPattern {
return pattern;
}

static AbstractionPattern
getCurriedCXXOperatorMethod(CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(nullptr, origType, method,
Kind::CurriedCXXOperatorMethodType);
return pattern;
}

/// For a C-function-as-method pattern,
/// get the index of the C function parameter that was imported as the
/// `self` parameter of the imported method, or None if this is a static
Expand Down Expand Up @@ -678,6 +718,17 @@ class AbstractionPattern {
return pattern;
}

static AbstractionPattern
getPartialCurriedCXXOperatorMethod(CanGenericSignature signature,
CanType origType,
const clang::CXXMethodDecl *method) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initCXXMethod(signature, origType, method,
Kind::PartialCurriedCXXOperatorMethodType);
return pattern;
}

public:
/// Return an abstraction pattern for the type of an Objective-C method.
static AbstractionPattern
Expand Down Expand Up @@ -813,6 +864,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
return OrigType;
Expand Down Expand Up @@ -849,6 +903,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
assert(signature || !type->hasTypeParameter());
Expand Down Expand Up @@ -886,6 +943,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
return true;
}
llvm_unreachable("bad kind");
Expand Down Expand Up @@ -923,7 +983,9 @@ class AbstractionPattern {
/// If so, it is legal to call getCXXMethod().
bool isCXXMethod() const {
return (getKind() == Kind::CXXMethodType ||
getKind() == Kind::CurriedCXXMethodType);
getKind() == Kind::CurriedCXXMethodType ||
getKind() == Kind::CXXOperatorMethodType ||
getKind() == Kind::CurriedCXXOperatorMethodType);
}

const clang::CXXMethodDecl *getCXXMethod() const {
Expand Down Expand Up @@ -958,6 +1020,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
Expand Down Expand Up @@ -994,6 +1059,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::Type:
case Kind::Discard:
return dyn_cast<TYPE>(getType());
Expand Down Expand Up @@ -1022,6 +1090,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
// We assume that the Clang type might provide additional structure.
Expand Down Expand Up @@ -1051,6 +1122,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
return false;
Expand Down Expand Up @@ -1078,6 +1152,9 @@ class AbstractionPattern {
case Kind::CXXMethodType:
case Kind::CurriedCXXMethodType:
case Kind::PartialCurriedCXXMethodType:
case Kind::CXXOperatorMethodType:
case Kind::CurriedCXXOperatorMethodType:
case Kind::PartialCurriedCXXOperatorMethodType:
case Kind::OpaqueFunction:
case Kind::OpaqueDerivativeFunction:
llvm_unreachable("pattern is not a tuple");
Expand Down
12 changes: 12 additions & 0 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3585,6 +3585,18 @@ void ClangImporter::Implementation::lookupValue(
auto &clangCtx = getClangASTContext();
auto clangTU = clangCtx.getTranslationUnitDecl();

// For operators we have to look up static member functions in addition to the
// top-level function lookup below.
if (name.isOperator()) {
for (auto entry : table.lookupMemberOperators(name.getBaseName())) {
if (isVisibleClangEntry(entry)) {
if (auto decl = dyn_cast<ValueDecl>(
importDeclReal(entry->getMostRecentDecl(), CurrentVersion)))
consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel);
}
}
}

for (auto entry : table.lookup(name.getBaseName(), clangTU)) {
// If the entry is not visible, skip it.
if (!isVisibleClangEntry(entry)) continue;
Expand Down
12 changes: 9 additions & 3 deletions lib/ClangImporter/ImportDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3812,14 +3812,20 @@ namespace {
decl->isVariadic(), isInSystemModule(dc), name, bodyParams);

if (auto *mdecl = dyn_cast<clang::CXXMethodDecl>(decl)) {
if (!mdecl->isStatic()) {
if (mdecl->isStatic() ||
// C++ operators that are implemented as non-static member
// functions get imported into Swift as static member functions
// that use an additional parameter for the left-hand side operand
// instead of the receiver object.
mdecl->getDeclName().getNameKind() ==
clang::DeclarationName::CXXOperatorName) {
selfIdx = None;
} else {
selfIdx = 0;
// Workaround until proper const support is handled: Force
// everything to be mutating. This implicitly makes the parameter
// indirect.
selfIsInOut = true;
} else {
selfIdx = None;
}
}
}
Expand Down
9 changes: 8 additions & 1 deletion lib/ClangImporter/ImportName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "swift/ClangImporter/ClangImporterOptions.h"
#include "swift/Parse/Parser.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/OperatorKinds.h"
Expand Down Expand Up @@ -1426,7 +1427,13 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
if (auto FD = dyn_cast<clang::FunctionDecl>(D)) {
baseName = clang::getOperatorSpelling(op);
isFunction = true;
argumentNames.resize(FD->param_size());
argumentNames.resize(
FD->param_size() +
// C++ operators that are implemented as non-static member functions
// get imported into Swift as static member functions that use an
// additional parameter for the left-hand side operand instead of
// the receiver object.
(isa<clang::CXXMethodDecl>(D) ? 1 : 0));
} else {
// This can happen for example for templated operators functions.
// We don't support those, yet.
Expand Down
26 changes: 26 additions & 0 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Type.h"
#include "swift/AST/Types.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Parse/Token.h"
#include "swift/Strings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Lex/Preprocessor.h"
Expand Down Expand Up @@ -1708,6 +1710,30 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
unsigned index = 0;
SmallBitVector nonNullArgs = getNonNullArgs(clangDecl, params);

// C++ operators that are implemented as non-static member functions get
// imported into Swift as static methods that have an additional
// parameter for the left-hand side operand instead of the receiver object.
if (auto CMD = dyn_cast<clang::CXXMethodDecl>(clangDecl)) {
if (clangDecl->isOverloadedOperator()) {
auto param = new (SwiftContext)
ParamDecl(SourceLoc(), SourceLoc(), Identifier(), SourceLoc(),
SwiftContext.getIdentifier("lhs"), dc);

auto parent = CMD->getParent();
auto parentType = importType(
parent->getASTContext().getRecordType(parent),
ImportTypeKind::Parameter, allowNSUIntegerAsInt, Bridgeability::None);

param->setInterfaceType(parentType.getType());

// Workaround until proper const support is handled: Force everything to
// be mutating. This implicitly makes the parameter indirect.
param->setSpecifier(ParamSpecifier::InOut);

parameters.push_back(param);
}
}

for (auto param : params) {
auto paramTy = param->getType();
if (paramTy->isVoidType()) {
Expand Down
30 changes: 30 additions & 0 deletions lib/ClangImporter/SwiftLookupTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "swift/AST/DiagnosticsClangImporter.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/Version.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
Expand Down Expand Up @@ -795,6 +796,35 @@ SwiftLookupTable::lookupObjCMembers(SerializedSwiftName baseName) {
return result;
}

SmallVector<clang::NamedDecl *, 4>
SwiftLookupTable::lookupMemberOperators(SerializedSwiftName baseName) {
SmallVector<clang::NamedDecl *, 4> result;

// Find the lookup table entry for this base name.
auto known = findOrCreate(LookupTable, baseName,
[](auto &results, auto &Reader, auto Name) {
return (void)Reader.lookup(Name, results);
});
if (known == LookupTable.end())
return result;

// Walk each of the entries.
for (auto &entry : known->second) {
// We're only looking for C++ operators
if (entry.Context.first != ContextKind::Tag) {
continue;
}

// Map each of the declarations.
for (auto &stored : entry.DeclsOrMacros) {
assert(isDeclEntry(stored) && "Not a declaration?");
result.push_back(mapStoredDecl(stored));
}
}

return result;
}

ArrayRef<clang::ObjCCategoryDecl *> SwiftLookupTable::categories() {
if (!Categories.empty() || !Reader) return Categories;

Expand Down
4 changes: 4 additions & 0 deletions lib/ClangImporter/SwiftLookupTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,10 @@ class SwiftLookupTable {
SmallVector<clang::NamedDecl *, 4>
lookupObjCMembers(SerializedSwiftName baseName);

/// Lookup member operators with the given base name, regardless of context.
SmallVector<clang::NamedDecl *, 4>
lookupMemberOperators(SerializedSwiftName baseName);

/// Retrieve the set of Objective-C categories and extensions.
ArrayRef<clang::ObjCCategoryDecl *> categories();

Expand Down
Loading