Skip to content

Commit 51efc38

Browse files
authored
Merge pull request #4922 from jckarter/nsvalue-bridging-3.0
[3.0] SE-0139: NSValue bridging
2 parents 4dea103 + c1e8ce6 commit 51efc38

40 files changed

+657
-108
lines changed

include/swift/AST/ASTContext.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,9 +514,9 @@ class ASTContext {
514514
ProtocolDecl *getProtocol(KnownProtocolKind kind) const;
515515

516516
/// Determine whether the given nominal type is one of the standard
517-
/// library types that is known a priori to be bridged to a
518-
/// Foundation.
519-
bool isStandardLibraryTypeBridgedInFoundation(NominalTypeDecl *nominal) const;
517+
/// library or Cocoa framework types that is known to be bridged by another
518+
/// module's overlay, for layering or implementation detail reasons.
519+
bool isTypeBridgedInExternalModule(NominalTypeDecl *nominal) const;
520520

521521
/// Get the Objective-C type that a Swift type bridges to, if any.
522522
///

include/swift/AST/Builtins.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,9 @@ BUILTIN_MISC_OPERATION(UnsafeGuaranteed, "unsafeGuaranteed", "", Special)
452452
// unsafeGuaranteedEnd has type (Builtin.Int8) -> ()
453453
BUILTIN_MISC_OPERATION(UnsafeGuaranteedEnd, "unsafeGuaranteedEnd", "", Special)
454454

455+
// getObjCTypeEncoding has type <T> T.Type -> RawPointer
456+
BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
457+
455458
#undef BUILTIN_MISC_OPERATION
456459

457460
// BUILTIN_TYPE_TRAIT_OPERATION - Compile-time type trait operations.

include/swift/AST/KnownIdentifiers.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ IDENTIFIER(Any)
2929
IDENTIFIER(atIndexedSubscript)
3030
IDENTIFIER_(bridgeToObjectiveC)
3131
IDENTIFIER_WITH_NAME(code_, "_code")
32+
IDENTIFIER(CoreGraphics)
33+
IDENTIFIER(CoreMedia)
3234
IDENTIFIER(CGFloat)
3335
IDENTIFIER(CVarArg)
3436
IDENTIFIER(Darwin)

lib/AST/ASTContext.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3982,7 +3982,7 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
39823982
}
39833983
}
39843984

3985-
bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
3985+
bool ASTContext::isTypeBridgedInExternalModule(
39863986
NominalTypeDecl *nominal) const {
39873987
return (nominal == getBoolDecl() ||
39883988
nominal == getIntDecl() ||
@@ -3995,8 +3995,18 @@ bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
39953995
nominal == getStringDecl() ||
39963996
nominal == getErrorDecl() ||
39973997
nominal == getAnyHashableDecl() ||
3998-
// Weird one-off case where CGFloat is bridged to NSNumber.
3999-
nominal->getName() == Id_CGFloat);
3998+
// Foundation's overlay depends on the CoreGraphics overlay, but
3999+
// CoreGraphics value types bridge to Foundation objects such as
4000+
// NSValue and NSNumber, so to avoid circular dependencies, the
4001+
// bridging implementations of CG types appear in the Foundation
4002+
// module.
4003+
nominal->getParentModule()->getName() == Id_CoreGraphics ||
4004+
// CoreMedia is a dependency of AVFoundation, but the bridged
4005+
// NSValue implementations for CMTime, CMTimeRange, and
4006+
// CMTimeMapping are provided by AVFoundation, and AVFoundation
4007+
// gets upset if you don't use the NSValue subclasses its factory
4008+
// methods instantiate.
4009+
nominal->getParentModule()->getName() == Id_CoreMedia);
40004010
}
40014011

40024012
Optional<Type>
@@ -4018,7 +4028,7 @@ ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
40184028
// optimizer will be guaranteed to see the conformance if it exists.
40194029
bool knownBridgedToObjC = false;
40204030
if (auto ntd = type->getAnyNominal())
4021-
knownBridgedToObjC = isStandardLibraryTypeBridgedInFoundation(ntd);
4031+
knownBridgedToObjC = isTypeBridgedInExternalModule(ntd);
40224032

40234033
// TODO: Under id-as-any, container bridging is unconstrained. This check can
40244034
// go away.

lib/AST/Builtins.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,15 @@ static ValueDecl *getZeroInitializerOperation(ASTContext &Context,
847847
return builder.build(Id);
848848
}
849849

850+
static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context,
851+
Identifier Id) {
852+
// <T> T.Type -> RawPointer
853+
GenericSignatureBuilder builder(Context);
854+
builder.addParameter(makeMetatype(makeGenericParam()));
855+
builder.setResult(makeConcrete(Context.TheRawPointerType));
856+
return builder.build(Id);
857+
}
858+
850859
static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
851860
// <T> (@inout T) -> RawPointer
852861
GenericSignatureBuilder builder(Context);
@@ -1626,6 +1635,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
16261635
case BuiltinValueKind::IntToFPWithOverflow:
16271636
if (Types.size() != 2) return nullptr;
16281637
return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]);
1638+
1639+
case BuiltinValueKind::GetObjCTypeEncoding:
1640+
return getGetObjCTypeEncodingOperation(Context, Id);
16291641
}
16301642

16311643
llvm_unreachable("bad builtin value!");

lib/IRGen/GenBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ADT/StringSwitch.h"
2323
#include "swift/AST/Types.h"
2424
#include "swift/SIL/SILModule.h"
25+
#include "clang/AST/ASTContext.h"
2526

2627
#include "Explosion.h"
2728
#include "GenCall.h"
@@ -852,5 +853,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
852853
return;
853854
}
854855

856+
if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) {
857+
args.claimAll();
858+
Type valueTy = substitutions[0].getReplacement();
859+
// Get the type encoding for the associated clang type.
860+
auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType());
861+
std::string encoding;
862+
IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding);
863+
864+
auto globalString = IGF.IGM.getAddrOfGlobalString(encoding);
865+
out.add(globalString);
866+
return;
867+
}
868+
855869
llvm_unreachable("IRGen unimplemented for this builtin!");
856870
}

lib/SIL/DynamicCasts.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,11 @@ mustBridgeToSwiftValueBox(Module *M, CanType T) {
5555
if (T->isAnyExistentialType())
5656
return false;
5757

58-
// getBridgedToObjC() might return a null-type for bridged foundation types
59-
// during compiling the standard library. Exclude this case here.
58+
// getBridgedToObjC() might return a null-type for some types
59+
// whose bridging implementation is allowed to live elsewhere. Exclude this
60+
// case here.
6061
if (auto N = T->getAnyNominal())
61-
if (M->getASTContext().isStandardLibraryTypeBridgedInFoundation(N))
62+
if (M->getASTContext().isTypeBridgedInExternalModule(N))
6263
return false;
6364

6465
auto bridgeTy = M->getASTContext().getBridgedToObjC(M, T, nullptr);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3904,7 +3904,7 @@ void ConformanceChecker::checkConformance() {
39043904
// between an imported Objective-C module and its overlay.
39053905
if (Proto->isSpecificProtocol(KnownProtocolKind::ObjectiveCBridgeable)) {
39063906
if (auto nominal = Adoptee->getAnyNominal()) {
3907-
if (!TC.Context.isStandardLibraryTypeBridgedInFoundation(nominal)) {
3907+
if (!TC.Context.isTypeBridgedInExternalModule(nominal)) {
39083908
auto nominalModule = nominal->getParentModule();
39093909
auto conformanceModule = DC->getParentModule();
39103910
if (nominalModule->getName() != conformanceModule->getName()) {

stdlib/private/StdlibUnittestFoundationExtras/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ add_swift_library(swiftStdlibUnittestFoundationExtras ${SWIFT_STDLIB_LIBRARY_BUI
44
StdlibUnittestFoundationExtras.swift
55
UnavailableFoundationMethodThunks.mm
66

7-
SWIFT_MODULE_DEPENDS Foundation
7+
SWIFT_MODULE_DEPENDS Foundation StdlibUnittest
88
INSTALL_IN_COMPONENT stdlib-experimental)
99

stdlib/private/StdlibUnittestFoundationExtras/StdlibUnittestFoundationExtras.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import ObjectiveC
1414
import Foundation
15+
import StdlibUnittest
1516

1617
internal var _temporaryLocaleCurrentLocale: NSLocale? = nil
1718

@@ -111,3 +112,20 @@ extension NSDictionary {
111112
andKeys: keys)
112113
}
113114
}
115+
116+
public func expectBridgeToNSValue<T>(_ value: T,
117+
nsValueInitializer: ((T) -> NSValue)? = nil,
118+
nsValueGetter: ((NSValue) -> T)? = nil,
119+
equal: (T, T) -> Bool) {
120+
let object = value as AnyObject
121+
let nsValue = object as! NSValue
122+
if let nsValueInitializer = nsValueInitializer {
123+
expectEqual(nsValueInitializer(value), nsValue)
124+
}
125+
if let nsValueGetter = nsValueGetter {
126+
expectTrue(equal(value, nsValueGetter(nsValue)))
127+
}
128+
expectTrue(equal(value, object as! T))
129+
130+
}
131+

0 commit comments

Comments
 (0)