Skip to content

Commit b0e3c0b

Browse files
authored
Merge pull request #4865 from jckarter/nsvalue-bridging
SE-0139: NSValue bridging
2 parents 2fd0896 + 86fbeee commit b0e3c0b

40 files changed

+656
-140
lines changed

include/swift/AST/ASTContext.h

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

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

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

include/swift/AST/Builtins.def

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

476+
// getObjCTypeEncoding has type <T> T.Type -> RawPointer
477+
BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)
478+
476479
#undef BUILTIN_MISC_OPERATION
477480

478481
// 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: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3945,7 +3945,7 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
39453945
}
39463946
}
39473947

3948-
bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
3948+
bool ASTContext::isTypeBridgedInExternalModule(
39493949
NominalTypeDecl *nominal) const {
39503950
return (nominal == getBoolDecl() ||
39513951
nominal == getIntDecl() ||
@@ -3958,8 +3958,18 @@ bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
39583958
nominal == getStringDecl() ||
39593959
nominal == getErrorDecl() ||
39603960
nominal == getAnyHashableDecl() ||
3961-
// Weird one-off case where CGFloat is bridged to NSNumber.
3962-
nominal->getName() == Id_CGFloat);
3961+
// Foundation's overlay depends on the CoreGraphics overlay, but
3962+
// CoreGraphics value types bridge to Foundation objects such as
3963+
// NSValue and NSNumber, so to avoid circular dependencies, the
3964+
// bridging implementations of CG types appear in the Foundation
3965+
// module.
3966+
nominal->getParentModule()->getName() == Id_CoreGraphics ||
3967+
// CoreMedia is a dependency of AVFoundation, but the bridged
3968+
// NSValue implementations for CMTime, CMTimeRange, and
3969+
// CMTimeMapping are provided by AVFoundation, and AVFoundation
3970+
// gets upset if you don't use the NSValue subclasses its factory
3971+
// methods instantiate.
3972+
nominal->getParentModule()->getName() == Id_CoreMedia);
39633973
}
39643974

39653975
Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,

lib/AST/Builtins.cpp

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

916+
static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context,
917+
Identifier Id) {
918+
// <T> T.Type -> RawPointer
919+
GenericSignatureBuilder builder(Context);
920+
builder.addParameter(makeMetatype(makeGenericParam()));
921+
builder.setResult(makeConcrete(Context.TheRawPointerType));
922+
return builder.build(Id);
923+
}
924+
916925
static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
917926
// <T> (@inout T) -> RawPointer
918927
GenericSignatureBuilder builder(Context);
@@ -1740,6 +1749,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
17401749
case BuiltinValueKind::IntToFPWithOverflow:
17411750
if (Types.size() != 2) return nullptr;
17421751
return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]);
1752+
1753+
case BuiltinValueKind::GetObjCTypeEncoding:
1754+
return getGetObjCTypeEncodingOperation(Context, Id);
17431755
}
17441756

17451757
llvm_unreachable("bad builtin value!");

lib/IRGen/GenBuiltin.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "swift/AST/Builtins.h"
2424
#include "swift/AST/Types.h"
2525
#include "swift/SIL/SILModule.h"
26+
#include "clang/AST/ASTContext.h"
2627

2728
#include "Explosion.h"
2829
#include "GenCall.h"
@@ -830,5 +831,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
830831
return;
831832
}
832833

834+
if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) {
835+
args.claimAll();
836+
Type valueTy = substitutions[0].getReplacement();
837+
// Get the type encoding for the associated clang type.
838+
auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType());
839+
std::string encoding;
840+
IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding);
841+
842+
auto globalString = IGF.IGM.getAddrOfGlobalString(encoding);
843+
out.add(globalString);
844+
return;
845+
}
846+
833847
llvm_unreachable("IRGen unimplemented for this builtin!");
834848
}

lib/SIL/DynamicCasts.cpp

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

47-
// getBridgedToObjC() might return a null-type for bridged foundation types
48-
// during compiling the standard library. Exclude this case here.
47+
// getBridgedToObjC() might return a null-type for some types
48+
// whose bridging implementation is allowed to live elsewhere. Exclude this
49+
// case here.
4950
if (auto N = T->getAnyNominal())
50-
if (M->getASTContext().isStandardLibraryTypeBridgedInFoundation(N))
51+
if (M->getASTContext().isTypeBridgedInExternalModule(N))
5152
return false;
5253

5354
return !M->getASTContext().getBridgedToObjC(M, T);

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3974,7 +3974,7 @@ void ConformanceChecker::checkConformance() {
39743974
// between an imported Objective-C module and its overlay.
39753975
if (Proto->isSpecificProtocol(KnownProtocolKind::ObjectiveCBridgeable)) {
39763976
if (auto nominal = Adoptee->getAnyNominal()) {
3977-
if (!TC.Context.isStandardLibraryTypeBridgedInFoundation(nominal)) {
3977+
if (!TC.Context.isTypeBridgedInExternalModule(nominal)) {
39783978
auto nominalModule = nominal->getParentModule();
39793979
auto conformanceModule = DC->getParentModule();
39803980
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?
1718

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

stdlib/public/SDK/AVFoundation/AVFoundation.swift renamed to stdlib/public/SDK/AVFoundation/AVFoundation.swift.gyb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
@_exported import AVFoundation // Clang module
2+
import CoreMedia
23
import Foundation
34

5+
%{
6+
from gyb_foundation_support import \
7+
ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods
8+
}%
49

510
extension AVError {
611
/// The device name.
@@ -39,3 +44,23 @@ extension AVError {
3944
}
4045
}
4146

47+
// Bridge CoreMedia structs to NSValue.
48+
// AVFoundation provides internal NSValue subclasses for these structures that
49+
// are incompatible with the NSConcreteValue subclasses you get using
50+
// -[NSValue valueWithBytes:objCType:].
51+
52+
${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
53+
Type="CMTime",
54+
initializer="{ NSValue(time: $0) }",
55+
getter="{ $0.timeValue }",
56+
) }
57+
${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
58+
Type="CMTimeRange",
59+
initializer="{ NSValue(timeRange: $0) }",
60+
getter="{ $0.timeRangeValue }",
61+
) }
62+
${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
63+
Type="CMTimeMapping",
64+
initializer="{ NSValue(timeMapping: $0) }",
65+
getter="{ $0.timeMappingValue }",
66+
) }

stdlib/public/SDK/AVFoundation/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
add_swift_library(swiftAVFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2-
AVFoundation.swift
2+
AVFoundation.swift.gyb
33
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
44
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
55
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"

stdlib/public/SDK/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ add_subdirectory(GLKit)
2929
add_subdirectory(HomeKit)
3030
add_subdirectory(IOKit)
3131
add_subdirectory(Intents)
32+
add_subdirectory(MapKit)
3233
add_subdirectory(ObjectiveC)
3334
add_subdirectory(OpenCL)
3435
add_subdirectory(os)
3536
add_subdirectory(Photos)
37+
add_subdirectory(QuartzCore)
3638
add_subdirectory(SafariServices)
3739
add_subdirectory(SceneKit)
3840
add_subdirectory(simd)

stdlib/public/SDK/CoreImage/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ add_swift_library(swiftCoreImage ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK
44
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
55
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
66
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
7-
SWIFT_MODULE_DEPENDS Foundation ObjectiveC
7+
SWIFT_MODULE_DEPENDS Foundation ObjectiveC QuartzCore
88
SWIFT_MODULE_DEPENDS_IOS CoreMedia
99
SWIFT_MODULE_DEPENDS_TVOS CoreMedia
1010
FRAMEWORK_DEPENDS_OSX QuartzCore

stdlib/public/SDK/CoreLocation/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
add_swift_library(swiftCoreLocation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2-
CoreLocation.swift
3-
2+
CoreLocation.swift.gyb
43
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
54
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
65
SWIFT_MODULE_DEPENDS Foundation

stdlib/public/SDK/CoreLocation/CoreLocation.swift renamed to stdlib/public/SDK/CoreLocation/CoreLocation.swift.gyb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
@_exported import CoreLocation
22
import Foundation
33

4+
%{
5+
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
6+
}%
7+
48
#if os(iOS)
59
extension CLError {
610
/// In a regionMonitoringResponseDelayed error, the region that the
@@ -10,3 +14,5 @@ extension CLError {
1014
}
1115
}
1216
#endif
17+
18+
${ ObjectiveCBridgeableImplementationForNSValue("CLLocationCoordinate2D") }

stdlib/public/SDK/Foundation/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ add_swift_library(swiftFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SD
33
Boxing.swift
44
NSError.swift
55
NSStringAPI.swift
6-
NSValue.swift
6+
NSValue.swift.gyb
77
ExtraStringAPIs.swift
88
ReferenceConvertible.swift
99
AffineTransform.swift

stdlib/public/SDK/Foundation/NSValue.swift

Lines changed: 0 additions & 39 deletions
This file was deleted.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//===--- NSValue.swift - Bridging things in NSValue -----------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
%{
14+
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
15+
}%
16+
17+
import CoreGraphics
18+
19+
${ ObjectiveCBridgeableImplementationForNSValue("NSRange") }
20+
${ ObjectiveCBridgeableImplementationForNSValue("CGRect") }
21+
${ ObjectiveCBridgeableImplementationForNSValue("CGPoint") }
22+
${ ObjectiveCBridgeableImplementationForNSValue("CGVector") }
23+
${ ObjectiveCBridgeableImplementationForNSValue("CGSize") }
24+
${ ObjectiveCBridgeableImplementationForNSValue("CGAffineTransform") }
25+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_swift_library(swiftMapKit ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2+
MapKit.swift.gyb
3+
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
4+
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
5+
SWIFT_MODULE_DEPENDS ObjectiveC Foundation
6+
SWIFT_MODULE_DEPENDS_IOS QuartzCore
7+
SWIFT_MODULE_DEPENDS_OSX QuartzCore AppKit
8+
SWIFT_MODULE_DEPENDS_TVOS QuartzCore
9+
FRAMEWORK_DEPENDS MapKit)
10+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@_exported import MapKit // Clang module
2+
import Foundation
3+
4+
%{
5+
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
6+
}%
7+
8+
${ ObjectiveCBridgeableImplementationForNSValue("MKCoordinateSpan") }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
add_swift_library(swiftQuartzCore ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2+
NSValue.swift.gyb
3+
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
4+
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
5+
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
6+
SWIFT_MODULE_DEPENDS ObjectiveC Foundation
7+
FRAMEWORK_DEPENDS QuartzCore)
8+
9+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===--- NSValue.swift - Bridging things in NSValue -----------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
%{
14+
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
15+
}%
16+
17+
@_exported import QuartzCore // Clang module
18+
import Foundation
19+
20+
${ ObjectiveCBridgeableImplementationForNSValue("CATransform3D") }
21+

0 commit comments

Comments
 (0)