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+

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_MODULE_DEPENDS Foundation CoreMedia
55
SWIFT_MODULE_DEPENDS_OSX AppKit

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
@@ -2,7 +2,7 @@ add_swift_library(swiftCoreImage ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK
22
CoreImage.swift
33

44
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
5-
SWIFT_MODULE_DEPENDS Foundation ObjectiveC
5+
SWIFT_MODULE_DEPENDS Foundation ObjectiveC QuartzCore
66
SWIFT_MODULE_DEPENDS_IOS CoreMedia
77
SWIFT_MODULE_DEPENDS_TVOS CoreMedia
88
FRAMEWORK_DEPENDS_OSX QuartzCore
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
add_swift_library(swiftCoreLocation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
2-
CoreLocation.swift
2+
CoreLocation.swift.gyb
33
SWIFT_MODULE_DEPENDS Foundation
44
FRAMEWORK_DEPENDS CoreLocation)

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+
QuartzCore.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)