Skip to content

Commit 6261ee2

Browse files
authored
Merge pull request #67772 from apple/egorzhdan/cxx-vector-proto
[cxx-interop] Add `CxxVector` protocol
2 parents 7020cf3 + 4acf9c8 commit 6261ee2

File tree

10 files changed

+148
-0
lines changed

10 files changed

+148
-0
lines changed

include/swift/AST/KnownProtocols.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ PROTOCOL(CxxSet)
115115
PROTOCOL(CxxRandomAccessCollection)
116116
PROTOCOL(CxxSequence)
117117
PROTOCOL(CxxUniqueSet)
118+
PROTOCOL(CxxVector)
118119
PROTOCOL(UnsafeCxxInputIterator)
119120
PROTOCOL(UnsafeCxxMutableInputIterator)
120121
PROTOCOL(UnsafeCxxRandomAccessIterator)

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
11391139
case KnownProtocolKind::CxxSet:
11401140
case KnownProtocolKind::CxxSequence:
11411141
case KnownProtocolKind::CxxUniqueSet:
1142+
case KnownProtocolKind::CxxVector:
11421143
case KnownProtocolKind::UnsafeCxxInputIterator:
11431144
case KnownProtocolKind::UnsafeCxxMutableInputIterator:
11441145
case KnownProtocolKind::UnsafeCxxRandomAccessIterator:

lib/ClangImporter/ClangDerivedConformances.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,3 +927,47 @@ void swift::conformToCxxDictionaryIfNeeded(
927927
insert->getResultInterfaceType());
928928
impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxDictionary});
929929
}
930+
931+
void swift::conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
932+
NominalTypeDecl *decl,
933+
const clang::CXXRecordDecl *clangDecl) {
934+
PrettyStackTraceDecl trace("conforming to CxxVector", decl);
935+
936+
assert(decl);
937+
assert(clangDecl);
938+
ASTContext &ctx = decl->getASTContext();
939+
940+
// Only auto-conform types from the C++ standard library. Custom user types
941+
// might have a similar interface but different semantics.
942+
if (!isStdDecl(clangDecl, {"vector"}))
943+
return;
944+
945+
auto valueType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
946+
decl, ctx.getIdentifier("value_type"));
947+
auto iterType = lookupDirectSingleWithoutExtensions<TypeAliasDecl>(
948+
decl, ctx.getIdentifier("const_iterator"));
949+
if (!valueType || !iterType)
950+
return;
951+
952+
ProtocolDecl *cxxRandomAccessIteratorProto =
953+
ctx.getProtocol(KnownProtocolKind::UnsafeCxxRandomAccessIterator);
954+
if (!cxxRandomAccessIteratorProto)
955+
return;
956+
957+
auto rawIteratorTy = iterType->getUnderlyingType();
958+
959+
// Check if RawIterator conforms to UnsafeCxxRandomAccessIterator.
960+
ModuleDecl *module = decl->getModuleContext();
961+
auto rawIteratorConformanceRef =
962+
module->lookupConformance(rawIteratorTy, cxxRandomAccessIteratorProto);
963+
if (!isConcreteAndValid(rawIteratorConformanceRef, module))
964+
return;
965+
966+
impl.addSynthesizedTypealias(decl, ctx.Id_Element,
967+
valueType->getUnderlyingType());
968+
impl.addSynthesizedTypealias(decl, ctx.Id_ArrayLiteralElement,
969+
valueType->getUnderlyingType());
970+
impl.addSynthesizedTypealias(decl, ctx.getIdentifier("RawIterator"),
971+
rawIteratorTy);
972+
impl.addSynthesizedProtocolAttrs(decl, {KnownProtocolKind::CxxVector});
973+
}

lib/ClangImporter/ClangDerivedConformances.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ void conformToCxxDictionaryIfNeeded(ClangImporter::Implementation &impl,
5959
NominalTypeDecl *decl,
6060
const clang::CXXRecordDecl *clangDecl);
6161

62+
/// If the decl is an instantiation of C++ `std::vector`, synthesize a
63+
/// conformance to CxxVector, which is defined in the Cxx module.
64+
void conformToCxxVectorIfNeeded(ClangImporter::Implementation &impl,
65+
NominalTypeDecl *decl,
66+
const clang::CXXRecordDecl *clangDecl);
67+
6268
} // namespace swift
6369

6470
#endif // SWIFT_CLANG_DERIVED_CONFORMANCES_H

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2797,6 +2797,7 @@ namespace {
27972797
conformToCxxDictionaryIfNeeded(Impl, nominalDecl, decl);
27982798
conformToCxxPairIfNeeded(Impl, nominalDecl, decl);
27992799
conformToCxxOptionalIfNeeded(Impl, nominalDecl, decl);
2800+
conformToCxxVectorIfNeeded(Impl, nominalDecl, decl);
28002801
}
28012802

28022803
if (auto *ntd = dyn_cast<NominalTypeDecl>(result))

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6310,6 +6310,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
63106310
case KnownProtocolKind::CxxSet:
63116311
case KnownProtocolKind::CxxSequence:
63126312
case KnownProtocolKind::CxxUniqueSet:
6313+
case KnownProtocolKind::CxxVector:
63136314
case KnownProtocolKind::UnsafeCxxInputIterator:
63146315
case KnownProtocolKind::UnsafeCxxMutableInputIterator:
63156316
case KnownProtocolKind::UnsafeCxxRandomAccessIterator:

stdlib/public/Cxx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ add_swift_target_library(swiftCxx ${SWIFT_CXX_LIBRARY_KIND} NO_LINK_NAME IS_STDL
1919
CxxSet.swift
2020
CxxRandomAccessCollection.swift
2121
CxxSequence.swift
22+
CxxVector.swift
2223
UnsafeCxxIterators.swift
2324

2425
SWIFT_COMPILE_FLAGS ${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS} ${SWIFT_STANDARD_LIBRARY_SWIFT_FLAGS}

stdlib/public/Cxx/CxxVector.swift

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// A C++ type that represents a vector of values.
14+
///
15+
/// C++ standard library type `std::vector` conforms to this protocol.
16+
public protocol CxxVector<Element>: ExpressibleByArrayLiteral {
17+
associatedtype Element
18+
associatedtype RawIterator: UnsafeCxxRandomAccessIterator
19+
where RawIterator.Pointee == Element
20+
21+
init()
22+
23+
mutating func push_back(_ element: Element)
24+
}
25+
26+
extension CxxVector {
27+
/// Creates a C++ vector containing the elements of a Swift Sequence.
28+
///
29+
/// This initializes the vector by copying every element of the sequence.
30+
///
31+
/// - Complexity: O(*n*), where *n* is the number of elements in the Swift
32+
/// sequence
33+
@inlinable
34+
public init<S: Sequence>(_ sequence: __shared S) where S.Element == Element {
35+
self.init()
36+
for item in sequence {
37+
self.push_back(item)
38+
}
39+
}
40+
}
41+
42+
extension CxxVector {
43+
@inlinable
44+
public init(arrayLiteral elements: Element...) {
45+
self.init(elements)
46+
}
47+
}

test/Interop/Cxx/stdlib/Inputs/std-vector.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ using VectorOfString = std::vector<std::string>;
99

1010
inline Vector initVector() { return {}; }
1111

12+
inline std::string takesVectorOfString(const VectorOfString &v) {
13+
return v.front();
14+
}
15+
1216
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_VECTOR_H

test/Interop/Cxx/stdlib/use-std-vector.swift

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,48 @@ StdVectorTestSuite.test("VectorOfInt.init") {
1919
expectTrue(v.empty())
2020
}
2121

22+
StdVectorTestSuite.test("VectorOfInt.init(sequence)") {
23+
let v = Vector([])
24+
expectEqual(v.size(), 0)
25+
expectTrue(v.empty())
26+
27+
let v2 = Vector([1, 2, 3])
28+
expectEqual(v2.size(), 3)
29+
expectFalse(v2.empty())
30+
expectEqual(v2[0], 1)
31+
expectEqual(v2[1], 2)
32+
expectEqual(v2[2], 3)
33+
}
34+
35+
StdVectorTestSuite.test("VectorOfString.init(sequence)") {
36+
let v = VectorOfString([])
37+
expectEqual(v.size(), 0)
38+
expectTrue(v.empty())
39+
40+
let v2 = VectorOfString(["", "ab", "abc"])
41+
expectEqual(v2.size(), 3)
42+
expectFalse(v2.empty())
43+
expectEqual(v2[0], "")
44+
expectEqual(v2[1], "ab")
45+
expectEqual(v2[2], "abc")
46+
47+
let first = takesVectorOfString(["abc", "qwe"])
48+
expectEqual(first, "abc")
49+
}
50+
51+
StdVectorTestSuite.test("VectorOfInt as ExpressibleByArrayLiteral") {
52+
let v: Vector = []
53+
expectEqual(v.size(), 0)
54+
expectTrue(v.empty())
55+
56+
let v2: Vector = [1, 2, 3]
57+
expectEqual(v2.size(), 3)
58+
expectFalse(v2.empty())
59+
expectEqual(v2[0], 1)
60+
expectEqual(v2[1], 2)
61+
expectEqual(v2[2], 3)
62+
}
63+
2264
StdVectorTestSuite.test("VectorOfInt.push_back") {
2365
var v = Vector()
2466
let _42: CInt = 42

0 commit comments

Comments
 (0)