Skip to content

Commit 6060557

Browse files
authored
Merge pull request #24316 from jrose-apple/its-like-a-burrito
[ClangImporter] Handle NS_TYPED_ENUMs of NSUIntegers in non-system headers
2 parents 8b4083a + 3498ca8 commit 6060557

File tree

5 files changed

+99
-64
lines changed

5 files changed

+99
-64
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 75 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,8 @@ namespace {
7171
/// The source type is 'void'.
7272
Void,
7373

74-
/// The source type is 'BOOL'.
75-
BOOL,
76-
77-
/// The source type is 'Boolean'.
74+
/// The source type is 'BOOL' or 'Boolean' -- a type mapped to Swift's
75+
/// 'Bool'.
7876
Boolean,
7977

8078
/// The source type is an Objective-C class type bridged to a Swift
@@ -129,7 +127,6 @@ namespace {
129127
// See also ClangImporter.cpp's canImportAsOptional.
130128
switch (hint) {
131129
case ImportHint::None:
132-
case ImportHint::BOOL:
133130
case ImportHint::Boolean:
134131
case ImportHint::NSUInteger:
135132
case ImportHint::Void:
@@ -667,24 +664,40 @@ namespace {
667664
if (!decl) return Visit(type->desugar());
668665

669666
Type mappedType = getAdjustedTypeDeclReferenceType(decl);
670-
ImportHint hint = ImportHint::None;
671667

672668
if (getSwiftNewtypeAttr(type->getDecl(), Impl.CurrentVersion)) {
673669
if (isCFTypeDecl(type->getDecl())) {
674-
hint = ImportHint::SwiftNewtypeFromCFPointer;
675-
} else {
670+
return {mappedType, ImportHint::SwiftNewtypeFromCFPointer};
671+
}
672+
673+
auto underlying = Visit(type->getDecl()->getUnderlyingType());
674+
switch (underlying.Hint) {
675+
case ImportHint::None:
676+
case ImportHint::Void:
677+
case ImportHint::Block:
678+
case ImportHint::CFPointer:
679+
case ImportHint::ObjCPointer:
680+
case ImportHint::CFunctionPointer:
681+
case ImportHint::OtherPointer:
682+
case ImportHint::SwiftNewtypeFromCFPointer:
683+
return {mappedType, underlying.Hint};
684+
685+
case ImportHint::Boolean:
686+
case ImportHint::NSUInteger:
687+
// Toss out the special rules for these types; we still want to
688+
// import as a wrapper.
689+
return {mappedType, ImportHint::None};
690+
691+
case ImportHint::ObjCBridged:
676692
// If the underlying type was bridged, the wrapper type is
677-
// only useful in bridged cases.
678-
auto underlying = Visit(type->getDecl()->getUnderlyingType());
679-
if (underlying.Hint == ImportHint::ObjCBridged) {
680-
return { underlying.AbstractType,
681-
ImportHint(ImportHint::ObjCBridged, mappedType) };
682-
}
683-
hint = underlying.Hint;
693+
// only useful in bridged cases. Exit early.
694+
return { underlying.AbstractType,
695+
ImportHint(ImportHint::ObjCBridged, mappedType) };
684696
}
697+
}
685698

686699
// For certain special typedefs, we don't want to use the imported type.
687-
} else if (auto specialKind = Impl.getSpecialTypedefKind(type->getDecl())) {
700+
if (auto specialKind = Impl.getSpecialTypedefKind(type->getDecl())) {
688701
switch (specialKind.getValue()) {
689702
case MappedTypeNameKind::DoNothing:
690703
case MappedTypeNameKind::DefineAndUse:
@@ -696,8 +709,9 @@ namespace {
696709
break;
697710
}
698711

712+
ImportHint hint = ImportHint::None;
699713
if (type->getDecl()->getName() == "BOOL") {
700-
hint = ImportHint::BOOL;
714+
hint = ImportHint::Boolean;
701715
} else if (type->getDecl()->getName() == "Boolean") {
702716
// FIXME: Darwin only?
703717
hint = ImportHint::Boolean;
@@ -711,64 +725,62 @@ namespace {
711725
hint = ImportHint::OtherPointer;
712726
}
713727
// Any other interesting mapped types should be hinted here.
728+
return { mappedType, hint };
729+
}
714730

715731
// Otherwise, recurse on the underlying type. We need to recompute
716732
// the hint, and if the typedef uses different bridgeability than the
717733
// context then we may also need to bypass the typedef.
718-
} else {
719-
auto underlyingType = type->desugar();
734+
auto underlyingType = type->desugar();
720735

721-
// Figure out the bridgeability we would normally use for this typedef.
722-
auto typedefBridgeability =
736+
// Figure out the bridgeability we would normally use for this typedef.
737+
auto typedefBridgeability =
723738
getTypedefBridgeability(type->getDecl(), underlyingType);
724739

725-
// Figure out the typedef we should actually use.
726-
auto underlyingBridgeability = Bridging;
727-
SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt,
728-
underlyingBridgeability);
729-
auto underlyingResult = innerConverter.Visit(underlyingType);
730-
731-
// If we used different bridgeability than this typedef normally
732-
// would because we're in a non-bridgeable context, and therefore
733-
// the underlying type is different from the mapping of the typedef,
734-
// use the underlying type.
735-
if (underlyingBridgeability != typedefBridgeability &&
736-
!underlyingResult.AbstractType->isEqual(mappedType)) {
737-
return underlyingResult;
738-
}
740+
// Figure out the typedef we should actually use.
741+
auto underlyingBridgeability = Bridging;
742+
SwiftTypeConverter innerConverter(Impl, AllowNSUIntegerAsInt,
743+
underlyingBridgeability);
744+
auto underlyingResult = innerConverter.Visit(underlyingType);
745+
746+
// If we used different bridgeability than this typedef normally
747+
// would because we're in a non-bridgeable context, and therefore
748+
// the underlying type is different from the mapping of the typedef,
749+
// use the underlying type.
750+
if (underlyingBridgeability != typedefBridgeability &&
751+
!underlyingResult.AbstractType->isEqual(mappedType)) {
752+
return underlyingResult;
753+
}
739754

740755
#ifndef NDEBUG
741-
switch (underlyingResult.Hint) {
742-
case ImportHint::Block:
743-
case ImportHint::ObjCBridged:
744-
// Bridging is fine for Objective-C and blocks.
756+
switch (underlyingResult.Hint) {
757+
case ImportHint::Block:
758+
case ImportHint::ObjCBridged:
759+
// Bridging is fine for Objective-C and blocks.
760+
break;
761+
case ImportHint::NSUInteger:
762+
// NSUInteger might be imported as Int rather than UInt depending
763+
// on where the import lives.
764+
if (underlyingResult.AbstractType->getAnyNominal() ==
765+
Impl.SwiftContext.getIntDecl())
745766
break;
746-
case ImportHint::NSUInteger:
747-
// NSUInteger might be imported as Int rather than UInt depending
748-
// on where the import lives.
749-
if (underlyingResult.AbstractType->getAnyNominal() ==
750-
Impl.SwiftContext.getIntDecl())
751-
break;
752-
LLVM_FALLTHROUGH;
753-
default:
754-
if (!underlyingResult.AbstractType->isEqual(mappedType)) {
755-
underlyingResult.AbstractType->dump();
756-
mappedType->dump();
757-
}
758-
assert(underlyingResult.AbstractType->isEqual(mappedType) &&
759-
"typedef without special typedef kind was mapped "
760-
"differently from its underlying type?");
767+
LLVM_FALLTHROUGH;
768+
default:
769+
if (!underlyingResult.AbstractType->isEqual(mappedType)) {
770+
underlyingResult.AbstractType->dump();
771+
mappedType->dump();
761772
}
773+
assert(underlyingResult.AbstractType->isEqual(mappedType) &&
774+
"typedef without special typedef kind was mapped "
775+
"differently from its underlying type?");
776+
}
762777
#endif
763-
hint = underlyingResult.Hint;
764778

765-
// If the imported typealias is unavailable, return the
766-
// underlying type.
767-
if (decl->getAttrs().isUnavailable(Impl.SwiftContext))
768-
mappedType = underlyingResult.AbstractType;
769-
}
779+
// If the imported typealias is unavailable, return the underlying type.
780+
if (decl->getAttrs().isUnavailable(Impl.SwiftContext))
781+
return underlyingResult;
770782

771-
return { mappedType, hint };
783+
return { mappedType, underlyingResult.Hint };
772784
}
773785

774786
#define SUGAR_TYPE(KIND) \
@@ -1365,8 +1377,8 @@ static ImportedType adjustTypeForConcreteImport(
13651377

13661378
// Turn BOOL and DarwinBoolean into Bool in contexts that can bridge types
13671379
// losslessly.
1368-
if ((hint == ImportHint::BOOL || hint == ImportHint::Boolean) &&
1369-
bridging == Bridgeability::Full && canBridgeTypes(importKind)) {
1380+
if (hint == ImportHint::Boolean && bridging == Bridgeability::Full &&
1381+
canBridgeTypes(importKind)) {
13701382
return {impl.SwiftContext.getBoolDecl()->getDeclaredType(), false};
13711383
}
13721384

test/ClangImporter/Inputs/custom-modules/Newtype.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,6 @@ typedef NSError *ErrorNewType __attribute((swift_newtype(struct)));
107107

108108
void testErrorDictionary(NSDictionary<NSError *, NSString *> * _Nonnull);
109109
void testErrorDictionaryNewtype(NSDictionary<ErrorNewType, NSString *> * _Nonnull);
110+
111+
typedef NSUInteger NSUIntegerNewType __attribute((swift_newtype(struct)));
112+
extern const NSUIntegerNewType NSUIntegerNewTypeConstant;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@import Foundation;
2+
3+
typedef NSUInteger NSUIntegerSystemNewType __attribute((swift_newtype(struct)));
4+
extern const NSUIntegerSystemNewType NSUIntegerSystemNewTypeConstant;
5+

test/ClangImporter/Inputs/custom-modules/module.map

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ module Newtype {
8787
header "Newtype.h"
8888
}
8989

90+
module NewtypeSystem [system] {
91+
header "NewtypeSystem.h"
92+
}
93+
9094
module ImportAsMember {
9195
export *
9296

@@ -224,4 +228,4 @@ module ConditionallyFoo {
224228

225229
module ForwardDeclarationsHelper {
226230
header "ForwardDeclarationsHelper.h"
227-
}
231+
}

test/ClangImporter/objc_parse.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import AppKit
66
import AVFoundation
77

88
import Newtype
9+
import NewtypeSystem
910
import objc_ext
1011
import TestProtocols
1112
import TypeAndValue
@@ -683,3 +684,13 @@ func testErrorNewtype() {
683684
testErrorDictionary(3) // expected-error {{cannot convert value of type 'Int' to expected argument type '[AnyHashable : String]'}}
684685
testErrorDictionaryNewtype(3) // expected-error {{cannot convert value of type 'Int' to expected argument type '[AnyHashable : String]'}}
685686
}
687+
688+
func testNSUIntegerNewtype() {
689+
let _: NSUIntegerNewType = NSUIntegerNewType(4)
690+
let _: UInt = NSUIntegerNewType(4).rawValue
691+
let _: NSUIntegerNewType = NSUIntegerNewType.constant
692+
693+
let _: NSUIntegerSystemNewType = NSUIntegerSystemNewType(4)
694+
let _: Int = NSUIntegerSystemNewType(4).rawValue
695+
let _: NSUIntegerSystemNewType = NSUIntegerSystemNewType.constant
696+
}

0 commit comments

Comments
 (0)