Skip to content

[cxx-interop][serialization] resolve x-refs to instantiated/synthesiz… #74524

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

Closed
wants to merge 1 commit into from
Closed
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
7 changes: 7 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,13 @@ bool isCFTypeDecl(const clang::TypedefNameDecl *Decl);
/// Determine the imported CF type for the given typedef-name, or the empty
/// string if this is not an imported CF type name.
llvm::StringRef getCFTypeName(const clang::TypedefNameDecl *decl);

/// Lookup and return the synthesized conformance operator like '==' '-' or '++'
/// for the given type.
ValueDecl *getSynthesizedConformanceOperator(const DeclBaseName &name,
NominalTypeDecl *selfType,
std::optional<Type> parameterType);

} // namespace importer

struct ClangInvocationFileMapping {
Expand Down
23 changes: 23 additions & 0 deletions lib/ClangImporter/ClangDerivedConformances.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,23 @@ bool swift::isIterator(const clang::CXXRecordDecl *clangDecl) {
return getIteratorCategoryDecl(clangDecl);
}

ValueDecl *swift::importer::getSynthesizedConformanceOperator(const DeclBaseName &name,
NominalTypeDecl *selfType,
std::optional<Type> parameterType) {
assert (name.isOperator());
if (name.getIdentifier() == selfType->getASTContext().Id_EqualsOperator) {
return getEqualEqualOperator(selfType);
}
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("-")) {
return getMinusOperator(selfType);
}
if (name.getIdentifier() == selfType->getASTContext().getIdentifier("+=") &&
parameterType) {
return getPlusEqualOperator(selfType, *parameterType);
}
return nullptr;
}

void swift::conformToCxxIteratorIfNeeded(
ClangImporter::Implementation &impl, NominalTypeDecl *decl,
const clang::CXXRecordDecl *clangDecl) {
Expand Down Expand Up @@ -504,6 +521,8 @@ void swift::conformToCxxIteratorIfNeeded(
equalEqual = getEqualEqualOperator(decl);
}
}
if (equalEqual)
equalEqual->setSynthesized();
}
if (!equalEqual)
return;
Expand Down Expand Up @@ -539,6 +558,8 @@ void swift::conformToCxxIteratorIfNeeded(
minus = getMinusOperator(decl);
}
}
if (minus)
minus->setSynthesized();
}
if (!minus)
return;
Expand All @@ -562,6 +583,8 @@ void swift::conformToCxxIteratorIfNeeded(
plusEqual = getPlusEqualOperator(decl, distanceTy);
}
}
if (plusEqual)
plusEqual->setSynthesized();
}
if (!plusEqual)
return;
Expand Down
28 changes: 24 additions & 4 deletions lib/Serialization/Deserialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2001,12 +2001,13 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
bool inProtocolExt = false;
bool importedFromClang = false;
bool isStatic = false;
bool isSynthesized = false;
if (isType)
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
inProtocolExt, importedFromClang);
else
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
importedFromClang, isStatic);
importedFromClang, isStatic, isSynthesized);

DeclBaseName name = getDeclBaseName(IID);
pathTrace.addValue(name);
Expand All @@ -2032,6 +2033,23 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
if (privateDiscriminator) {
baseModule->lookupMember(values, baseModule, name,
getIdentifier(privateDiscriminator));
} else if (isSynthesized && importedFromClang) {
ValueDecl *synthesizedResult = nullptr;
if (name.isOperator() && filterTy) {
// This is a Clang-importer synthesized conformance operator. Resolve it
// using clang importer lookup logic for the given type.
if (auto *fty = dyn_cast<AnyFunctionType>(filterTy.getPointer())) {
if (fty->getNumParams()) {
auto p = fty->getParams()[0].getParameterType();
if (auto sty = dyn_cast<NominalType>(p.getPointer()))
synthesizedResult = importer::getSynthesizedConformanceOperator(name, sty->getDecl(), fty->getNumParams() > 1 ? fty->getParams()[1].getParameterType() : std::optional<Type>{});
}
}
}
if (!synthesizedResult)
return llvm::make_error<XRefError>("couldn't find synthesized clang value decl x-ref",
pathTrace, name);
values.push_back(synthesizedResult);
} else {
baseModule->lookupQualified(baseModule, DeclNameRef(name),
SourceLoc(), NL_QualifiedDefault,
Expand Down Expand Up @@ -2133,7 +2151,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
IdentifierID IID;
XRefValuePathPieceLayout::readRecord(scratch, std::nullopt, IID,
std::nullopt, std::nullopt,
std::nullopt);
std::nullopt, std::nullopt);
result = getIdentifier(IID);
break;
}
Expand Down Expand Up @@ -2200,12 +2218,13 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
bool inProtocolExt = false;
bool importedFromClang = false;
bool isStatic = false;
bool isSynthesized = false;
if (isType) {
XRefTypePathPieceLayout::readRecord(scratch, IID, privateDiscriminator,
inProtocolExt, importedFromClang);
} else {
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
importedFromClang, isStatic);
importedFromClang, isStatic, isSynthesized);
}

DeclBaseName name = getDeclBaseName(IID);
Expand Down Expand Up @@ -2378,6 +2397,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
bool inProtocolExt = false;
bool importedFromClang = false;
bool isStatic = false;
bool isSynthesized = false;
switch (recordID) {
case XREF_TYPE_PATH_PIECE: {
IdentifierID IID, discriminatorID;
Expand All @@ -2392,7 +2412,7 @@ ModuleFile::resolveCrossReference(ModuleID MID, uint32_t pathLen) {
case XREF_VALUE_PATH_PIECE: {
IdentifierID IID;
XRefValuePathPieceLayout::readRecord(scratch, TID, IID, inProtocolExt,
importedFromClang, isStatic);
importedFromClang, isStatic, isSynthesized);
memberName = getDeclBaseName(IID);
break;
}
Expand Down
3 changes: 2 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -2089,7 +2089,8 @@ namespace decls_block {
IdentifierIDField, // name
BCFixed<1>, // restrict to protocol extension
BCFixed<1>, // imported from Clang?
BCFixed<1> // static?
BCFixed<1>, // static?
BCFixed<1> // synthesized?
>;

using XRefInitializerPathPieceLayout = BCRecordLayout<
Expand Down
8 changes: 4 additions & 4 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2198,7 +2198,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
addTypeRef(ty), SUBSCRIPT_ID,
isProtocolExt, SD->hasClangNode(),
SD->isStatic());
SD->isStatic(), SD->isSynthesized());
break;
}

Expand All @@ -2215,7 +2215,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
addTypeRef(ty), nameID,
isProtocolExt,
storage->hasClangNode(),
storage->isStatic());
storage->isStatic(), storage->isSynthesized());

abbrCode =
DeclTypeAbbrCodes[XRefOperatorOrAccessorPathPieceLayout::Code];
Expand Down Expand Up @@ -2250,7 +2250,7 @@ void Serializer::writeCrossReference(const DeclContext *DC, uint32_t pathLen) {
addTypeRef(ty),
addDeclBaseNameRef(fn->getBaseName()),
isProtocolExt, fn->hasClangNode(),
fn->isStatic());
fn->isStatic(), fn->isSynthesized());

if (fn->isOperator()) {
// Encode the fixity as a filter on the func decls, to distinguish prefix
Expand Down Expand Up @@ -2357,7 +2357,7 @@ void Serializer::writeCrossReference(const Decl *D) {
IdentifierID iid = addDeclBaseNameRef(val->getBaseName());
XRefValuePathPieceLayout::emitRecord(Out, ScratchRecord, abbrCode,
addTypeRef(ty), iid, isProtocolExt,
D->hasClangNode(), val->isStatic());
D->hasClangNode(), val->isStatic(), val->isSynthesized());
}

/// Translate from the AST associativity enum to the Serialization enum
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %empty-directory(%t)
// RUN: %target-swiftxx-frontend -emit-module %s -module-name TestA -I %S/Inputs -o %t/test-part.swiftmodule
// RUN: %target-swiftxx-frontend -merge-modules -emit-module %t/test-part.swiftmodule -module-name TestA -I %S/Inputs -o %t/TestA.swiftmodule -sil-verify-none
// RUN: %target-typecheck-verify-swift -I %S/Inputs -cxx-interoperability-mode=default -I %t

#if USE

import TestA

public func test() {
print(testEqualEqual())
}

#else

import CustomSequence

@inlinable
public func testEqualEqual() -> Bool {
let m = HasInheritedConstIterator()
return m.__beginUnsafe() == m.__endUnsafe()
}

#endif