Skip to content

SE-0139: NSValue bridging #4865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,9 +510,9 @@ class ASTContext {
ProtocolDecl *getProtocol(KnownProtocolKind kind) const;

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

/// Get the Objective-C type that a Swift type bridges to, if any.
///
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/Builtins.def
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,9 @@ BUILTIN_MISC_OPERATION(UnsafeGuaranteed, "unsafeGuaranteed", "", Special)
// unsafeGuaranteedEnd has type (Builtin.Int8) -> ()
BUILTIN_MISC_OPERATION(UnsafeGuaranteedEnd, "unsafeGuaranteedEnd", "", Special)

// getObjCTypeEncoding has type <T> T.Type -> RawPointer
BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special)

#undef BUILTIN_MISC_OPERATION

// BUILTIN_TYPE_TRAIT_OPERATION - Compile-time type trait operations.
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ IDENTIFIER(Any)
IDENTIFIER(atIndexedSubscript)
IDENTIFIER_(bridgeToObjectiveC)
IDENTIFIER_WITH_NAME(code_, "_code")
IDENTIFIER(CoreGraphics)
IDENTIFIER(CoreMedia)
IDENTIFIER(CGFloat)
IDENTIFIER(CVarArg)
IDENTIFIER(Darwin)
Expand Down
16 changes: 13 additions & 3 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3938,7 +3938,7 @@ ASTContext::getForeignRepresentationInfo(NominalTypeDecl *nominal,
}
}

bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
bool ASTContext::isTypeBridgedInExternalModule(
NominalTypeDecl *nominal) const {
return (nominal == getBoolDecl() ||
nominal == getIntDecl() ||
Expand All @@ -3951,8 +3951,18 @@ bool ASTContext::isStandardLibraryTypeBridgedInFoundation(
nominal == getStringDecl() ||
nominal == getErrorDecl() ||
nominal == getAnyHashableDecl() ||
// Weird one-off case where CGFloat is bridged to NSNumber.
nominal->getName() == Id_CGFloat);
// Foundation's overlay depends on the CoreGraphics overlay, but
// CoreGraphics value types bridge to Foundation objects such as
// NSValue and NSNumber, so to avoid circular dependencies, the
// bridging implementations of CG types appear in the Foundation
// module.
nominal->getParentModule()->getName() == Id_CoreGraphics ||
// CoreMedia is a dependency of AVFoundation, but the bridged
// NSValue implementations for CMTime, CMTimeRange, and
// CMTimeMapping are provided by AVFoundation, and AVFoundation
// gets upset if you don't use the NSValue subclasses its factory
// methods instantiate.
nominal->getParentModule()->getName() == Id_CoreMedia);
}

Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
Expand Down
12 changes: 12 additions & 0 deletions lib/AST/Builtins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,15 @@ static ValueDecl *getZeroInitializerOperation(ASTContext &Context,
return builder.build(Id);
}

static ValueDecl *getGetObjCTypeEncodingOperation(ASTContext &Context,
Identifier Id) {
// <T> T.Type -> RawPointer
GenericSignatureBuilder builder(Context);
builder.addParameter(makeMetatype(makeGenericParam()));
builder.setResult(makeConcrete(Context.TheRawPointerType));
return builder.build(Id);
}

static ValueDecl *getAddressOfOperation(ASTContext &Context, Identifier Id) {
// <T> (@inout T) -> RawPointer
GenericSignatureBuilder builder(Context);
Expand Down Expand Up @@ -1740,6 +1749,9 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) {
case BuiltinValueKind::IntToFPWithOverflow:
if (Types.size() != 2) return nullptr;
return getIntToFPWithOverflowOperation(Context, Id, Types[0], Types[1]);

case BuiltinValueKind::GetObjCTypeEncoding:
return getGetObjCTypeEncodingOperation(Context, Id);
}

llvm_unreachable("bad builtin value!");
Expand Down
14 changes: 14 additions & 0 deletions lib/IRGen/GenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "swift/AST/Builtins.h"
#include "swift/AST/Types.h"
#include "swift/SIL/SILModule.h"
#include "clang/AST/ASTContext.h"

#include "Explosion.h"
#include "GenCall.h"
Expand Down Expand Up @@ -830,5 +831,18 @@ if (Builtin.ID == BuiltinValueKind::id) { \
return;
}

if (Builtin.ID == BuiltinValueKind::GetObjCTypeEncoding) {
args.claimAll();
Type valueTy = substitutions[0].getReplacement();
// Get the type encoding for the associated clang type.
auto clangTy = IGF.IGM.getClangType(valueTy->getCanonicalType());
std::string encoding;
IGF.IGM.getClangASTContext().getObjCEncodingForType(clangTy, encoding);

auto globalString = IGF.IGM.getAddrOfGlobalString(encoding);
out.add(globalString);
return;
}

llvm_unreachable("IRGen unimplemented for this builtin!");
}
7 changes: 4 additions & 3 deletions lib/SIL/DynamicCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ mustBridgeToSwiftValueBox(Module *M, CanType T) {
if (T->isAnyExistentialType())
return false;

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

return !M->getASTContext().getBridgedToObjC(M, T);
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3974,7 +3974,7 @@ void ConformanceChecker::checkConformance() {
// between an imported Objective-C module and its overlay.
if (Proto->isSpecificProtocol(KnownProtocolKind::ObjectiveCBridgeable)) {
if (auto nominal = Adoptee->getAnyNominal()) {
if (!TC.Context.isStandardLibraryTypeBridgedInFoundation(nominal)) {
if (!TC.Context.isTypeBridgedInExternalModule(nominal)) {
auto nominalModule = nominal->getParentModule();
auto conformanceModule = DC->getParentModule();
if (nominalModule->getName() != conformanceModule->getName()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ add_swift_library(swiftStdlibUnittestFoundationExtras ${SWIFT_STDLIB_LIBRARY_BUI
StdlibUnittestFoundationExtras.swift
UnavailableFoundationMethodThunks.mm

SWIFT_MODULE_DEPENDS Foundation
SWIFT_MODULE_DEPENDS Foundation StdlibUnittest
INSTALL_IN_COMPONENT stdlib-experimental)

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import ObjectiveC
import Foundation
import StdlibUnittest

internal var _temporaryLocaleCurrentLocale: NSLocale?

Expand Down Expand Up @@ -113,3 +114,20 @@ extension NSDictionary {
andKeys: keys)
}
}

public func expectBridgeToNSValue<T>(_ value: T,
nsValueInitializer: ((T) -> NSValue)? = nil,
nsValueGetter: ((NSValue) -> T)? = nil,
equal: (T, T) -> Bool) {
let object = value as AnyObject
let nsValue = object as! NSValue
if let nsValueInitializer = nsValueInitializer {
expectEqual(nsValueInitializer(value), nsValue)
}
if let nsValueGetter = nsValueGetter {
expectTrue(equal(value, nsValueGetter(nsValue)))
}
expectTrue(equal(value, object as! T))

}

Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
@_exported import AVFoundation // Clang module
import CoreMedia
import Foundation

%{
from gyb_foundation_support import \
ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods
}%

extension AVError {
/// The device name.
Expand Down Expand Up @@ -39,3 +44,23 @@ extension AVError {
}
}

// Bridge CoreMedia structs to NSValue.
// AVFoundation provides internal NSValue subclasses for these structures that
// are incompatible with the NSConcreteValue subclasses you get using
// -[NSValue valueWithBytes:objCType:].

${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
Type="CMTime",
initializer="{ NSValue(time: $0) }",
getter="{ $0.timeValue }",
) }
${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
Type="CMTimeRange",
initializer="{ NSValue(timeRange: $0) }",
getter="{ $0.timeRangeValue }",
) }
${ ObjectiveCBridgeableImplementationForNSValueWithCategoryMethods(
Type="CMTimeMapping",
initializer="{ NSValue(timeMapping: $0) }",
getter="{ $0.timeMappingValue }",
) }
2 changes: 1 addition & 1 deletion stdlib/public/SDK/AVFoundation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
add_swift_library(swiftAVFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
AVFoundation.swift
AVFoundation.swift.gyb
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
Expand Down
2 changes: 2 additions & 0 deletions stdlib/public/SDK/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ add_subdirectory(GLKit)
add_subdirectory(HomeKit)
add_subdirectory(IOKit)
add_subdirectory(Intents)
add_subdirectory(MapKit)
add_subdirectory(ObjectiveC)
add_subdirectory(OpenCL)
add_subdirectory(os)
add_subdirectory(Photos)
add_subdirectory(QuartzCore)
add_subdirectory(SafariServices)
add_subdirectory(SceneKit)
add_subdirectory(simd)
Expand Down
2 changes: 1 addition & 1 deletion stdlib/public/SDK/CoreImage/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ add_swift_library(swiftCoreImage ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
SWIFT_MODULE_DEPENDS Foundation ObjectiveC
SWIFT_MODULE_DEPENDS Foundation ObjectiveC QuartzCore
SWIFT_MODULE_DEPENDS_IOS CoreMedia
SWIFT_MODULE_DEPENDS_TVOS CoreMedia
FRAMEWORK_DEPENDS_OSX QuartzCore
Expand Down
3 changes: 1 addition & 2 deletions stdlib/public/SDK/CoreLocation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
add_swift_library(swiftCoreLocation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
CoreLocation.swift

CoreLocation.swift.gyb
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
SWIFT_MODULE_DEPENDS Foundation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
@_exported import CoreLocation
import Foundation

%{
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
}%

#if os(iOS)
extension CLError {
/// In a regionMonitoringResponseDelayed error, the region that the
Expand All @@ -10,3 +14,5 @@ extension CLError {
}
}
#endif

${ ObjectiveCBridgeableImplementationForNSValue("CLLocationCoordinate2D") }
2 changes: 1 addition & 1 deletion stdlib/public/SDK/Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ add_swift_library(swiftFoundation ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SD
Boxing.swift
NSError.swift
NSStringAPI.swift
NSValue.swift
NSValue.swift.gyb
ExtraStringAPIs.swift
ReferenceConvertible.swift
AffineTransform.swift
Expand Down
39 changes: 0 additions & 39 deletions stdlib/public/SDK/Foundation/NSValue.swift

This file was deleted.

25 changes: 25 additions & 0 deletions stdlib/public/SDK/Foundation/NSValue.swift.gyb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===--- NSValue.swift - Bridging things in NSValue -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

%{
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
}%

import CoreGraphics

${ ObjectiveCBridgeableImplementationForNSValue("NSRange") }
${ ObjectiveCBridgeableImplementationForNSValue("CGRect") }
${ ObjectiveCBridgeableImplementationForNSValue("CGPoint") }
${ ObjectiveCBridgeableImplementationForNSValue("CGVector") }
${ ObjectiveCBridgeableImplementationForNSValue("CGSize") }
${ ObjectiveCBridgeableImplementationForNSValue("CGAffineTransform") }

10 changes: 10 additions & 0 deletions stdlib/public/SDK/MapKit/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_swift_library(swiftMapKit ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
MapKit.swift.gyb
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
SWIFT_MODULE_DEPENDS ObjectiveC Foundation
SWIFT_MODULE_DEPENDS_IOS QuartzCore
SWIFT_MODULE_DEPENDS_OSX QuartzCore AppKit
SWIFT_MODULE_DEPENDS_TVOS QuartzCore
FRAMEWORK_DEPENDS MapKit)

8 changes: 8 additions & 0 deletions stdlib/public/SDK/MapKit/MapKit.swift.gyb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@_exported import MapKit // Clang module
import Foundation

%{
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
}%

${ ObjectiveCBridgeableImplementationForNSValue("MKCoordinateSpan") }
9 changes: 9 additions & 0 deletions stdlib/public/SDK/QuartzCore/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_swift_library(swiftQuartzCore ${SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES} IS_SDK_OVERLAY
NSValue.swift.gyb
SWIFT_COMPILE_FLAGS "${SWIFT_RUNTIME_SWIFT_COMPILE_FLAGS}"
LINK_FLAGS "${SWIFT_RUNTIME_SWIFT_LINK_FLAGS}"
TARGET_SDKS OSX IOS IOS_SIMULATOR TVOS TVOS_SIMULATOR
SWIFT_MODULE_DEPENDS ObjectiveC Foundation
FRAMEWORK_DEPENDS QuartzCore)


21 changes: 21 additions & 0 deletions stdlib/public/SDK/QuartzCore/NSValue.swift.gyb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===--- NSValue.swift - Bridging things in NSValue -----------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

%{
from gyb_foundation_support import ObjectiveCBridgeableImplementationForNSValue
}%

@_exported import QuartzCore // Clang module
import Foundation

${ ObjectiveCBridgeableImplementationForNSValue("CATransform3D") }

Loading