Skip to content

Commit f9bd1a5

Browse files
authored
Merge pull request #66452 from zoecarver/ns-option-as-field-take-two
2 parents 63ee747 + 3f45c17 commit f9bd1a5

File tree

4 files changed

+63
-11
lines changed

4 files changed

+63
-11
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,11 +3595,30 @@ namespace {
35953595
return nullptr;
35963596
}
35973597

3598-
auto importedType =
3599-
Impl.importType(decl->getType(), ImportTypeKind::RecordField,
3600-
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
3601-
isInSystemModule(dc), Bridgeability::None,
3602-
getImportTypeAttrs(decl));
3598+
ImportedType importedType;
3599+
auto fieldType = decl->getType();
3600+
if (auto elaborated = dyn_cast<clang::ElaboratedType>(fieldType))
3601+
fieldType = elaborated->desugar();
3602+
if (auto typedefType = dyn_cast<clang::TypedefType>(fieldType)) {
3603+
if (Impl.isUnavailableInSwift(typedefType->getDecl())) {
3604+
if (auto clangEnum = findAnonymousEnumForTypedef(Impl.SwiftContext, typedefType)) {
3605+
// If this fails, it means that we need a stronger predicate for
3606+
// determining the relationship between an enum and typedef.
3607+
assert(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
3608+
typedefType->getCanonicalTypeInternal());
3609+
if (auto swiftEnum = Impl.importDecl(*clangEnum, Impl.CurrentVersion)) {
3610+
importedType = {cast<TypeDecl>(swiftEnum)->getDeclaredInterfaceType(), false};
3611+
}
3612+
}
3613+
}
3614+
}
3615+
3616+
if (!importedType)
3617+
importedType =
3618+
Impl.importType(decl->getType(), ImportTypeKind::RecordField,
3619+
ImportDiagnosticAdder(Impl, decl, decl->getLocation()),
3620+
isInSystemModule(dc), Bridgeability::None,
3621+
getImportTypeAttrs(decl));
36033622
if (!importedType) {
36043623
Impl.addImportDiagnostic(
36053624
decl, Diagnostic(diag::record_field_not_imported, decl),
@@ -5828,6 +5847,13 @@ SwiftDeclConverter::importAsOptionSetType(DeclContext *dc, Identifier name,
58285847
const clang::EnumDecl *decl) {
58295848
ASTContext &ctx = Impl.SwiftContext;
58305849

5850+
auto Loc = Impl.importSourceLoc(decl->getLocation());
5851+
5852+
// Create a struct with the underlying type as a field.
5853+
auto structDecl = Impl.createDeclWithClangNode<StructDecl>(
5854+
decl, AccessLevel::Public, Loc, name, Loc, None, nullptr, dc);
5855+
Impl.ImportedDecls[{decl->getCanonicalDecl(), getVersion()}] = structDecl;
5856+
58315857
// Compute the underlying type.
58325858
auto underlyingType = Impl.importTypeIgnoreIUO(
58335859
decl->getIntegerType(), ImportTypeKind::Enum,
@@ -5836,12 +5862,6 @@ SwiftDeclConverter::importAsOptionSetType(DeclContext *dc, Identifier name,
58365862
if (!underlyingType)
58375863
return nullptr;
58385864

5839-
auto Loc = Impl.importSourceLoc(decl->getLocation());
5840-
5841-
// Create a struct with the underlying type as a field.
5842-
auto structDecl = Impl.createDeclWithClangNode<StructDecl>(
5843-
decl, AccessLevel::Public, Loc, name, Loc, None, nullptr, dc);
5844-
58455865
synthesizer.makeStructRawValued(structDecl, underlyingType,
58465866
{KnownProtocolKind::OptionSet});
58475867
auto selfType = structDecl->getDeclaredInterfaceType();

test/Interop/Cxx/enum/Inputs/c-enums-NS_OPTIONS.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ typedef NS_OPTIONS(NSUInteger, Bar) {
8181

8282
typedef NS_OPTIONS(NSUInteger, Baz) { Baz1, Baz2 };
8383

84+
struct HasNSOptionField {
85+
Bar bar;
86+
};
87+
8488
Baz CFunctionReturningNSOption();
8589
void CFunctionTakingNSOption(Baz);
8690

test/Interop/Cxx/enum/c-enums-NS_OPTIONS.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@ import CenumsNSOptions
2020
// CHECK-NEXT: @available(swift, obsoleted: 3, renamed: "insertionIndex")
2121
// CHECK-NEXT: static var InsertionIndex: NSBinarySearchingOptions { get }
2222
// CHECK-NEXT: }
23+
24+
// CHECK: struct Bar : OptionSet, @unchecked Sendable
25+
// CHECK: struct HasNSOptionField {
26+
// CHECK: var bar: Bar
27+
// CHECK: }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: executable_test
5+
6+
import CenumsNSOptions
7+
import StdlibUnittest
8+
9+
var FieldTestSuite = TestSuite("NS_Option as field")
10+
11+
struct HasNSOptionMember {
12+
var member: Bar
13+
}
14+
15+
FieldTestSuite.test("NSOption as field") {
16+
var parent = HasNSOptionMember(member: [.SwiftOptionOneApiNotes, .SwiftOptionTwoApiNotes])
17+
expectEqual(parent.member, [.SwiftOptionOneApiNotes, .SwiftOptionTwoApiNotes])
18+
19+
parent.member = [.SwiftOptionOneApiNotes]
20+
expectNotEqual(parent.member, [.SwiftOptionOneApiNotes, .SwiftOptionTwoApiNotes])
21+
}
22+
23+
runAllTests()

0 commit comments

Comments
 (0)