Skip to content

Turn on 'as' bridging for Linux (2) #16736

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
May 31, 2018
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
19 changes: 8 additions & 11 deletions lib/SIL/DynamicCasts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,22 +1139,19 @@ bool swift::canUseScalarCheckedCastInstructions(SILModule &M,
if (!objectType.isAnyClassReferenceType())
return false;

if (M.getASTContext().LangOpts.EnableObjCInterop) {
auto super = archetype->getSuperclass();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation here should be fixed to match the surrounding code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok!

if (super.isNull())
return false;

// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
// If NSError wasn't loaded, any base class constraint must not be NSError.
return true;
} else {
// If ObjC bridging isn't enabled, we can do a scalar cast from any
// reference type to any class-constrained archetype.
return archetype->requiresClass();
// A base class constraint that isn't NSError rules out the archetype being
// bound to NSError.
if (M.getASTContext().LangOpts.EnableObjCInterop) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every other change here seems to be about removing such calls, why does this remain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been introducing the minimum change that supports the subset we need in s-c-f by elimination. A follow-up will be to add tests, and revisit paths here if we find corner cases that I missed.

if (auto nserror = M.Types.getNSErrorType())
return !super->isEqual(nserror);
}

// If NSError wasn't loaded, any base class constraint must not be NSError.
return true;
}

if (M.getASTContext().LangOpts.EnableObjCInterop
Expand Down
5 changes: 1 addition & 4 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3660,10 +3660,7 @@ namespace {
auto *locator = cs.getConstraintLocator(expr);

if (!choice) {
if (tc.Context.LangOpts.EnableObjCInterop)
choice = solution.getDisjunctionChoice(locator);
else
choice = 0;
choice = solution.getDisjunctionChoice(locator);
}

// Handle the coercion/bridging of the underlying subexpression, where
Expand Down
22 changes: 7 additions & 15 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3637,11 +3637,6 @@ ConstraintSystem::simplifyBridgingConstraint(Type type1,
Type type2,
TypeMatchOptions flags,
ConstraintLocatorBuilder locator) {
// There's no bridging without ObjC interop, so we shouldn't have set up
// bridging constraints without it.
assert(TC.Context.LangOpts.EnableObjCInterop
&& "bridging constraint w/o ObjC interop?!");

TypeMatchOptions subflags = getDefaultDecompositionOptions(flags);

/// Form an unresolved result.
Expand Down Expand Up @@ -5086,14 +5081,11 @@ void ConstraintSystem::addExplicitConversionConstraint(
coerceConstraint->setFavored();
constraints.push_back(coerceConstraint);

// Bridging.
if (getASTContext().LangOpts.EnableObjCInterop) {
// The source type can be explicitly converted to the destination type.
Constraint *bridgingConstraint =
Constraint::create(*this, ConstraintKind::BridgingConversion,
fromType, toType, locatorPtr);
constraints.push_back(bridgingConstraint);
}
// The source type can be explicitly converted to the destination type.
Constraint *bridgingConstraint =
Constraint::create(*this, ConstraintKind::BridgingConversion,
fromType, toType, locatorPtr);
constraints.push_back(bridgingConstraint);

if (allowFixes && shouldAttemptFixes()) {
Constraint *downcastConstraint =
Expand All @@ -5104,8 +5096,8 @@ void ConstraintSystem::addExplicitConversionConstraint(
}

addDisjunctionConstraint(constraints, locator,
getASTContext().LangOpts.EnableObjCInterop && allowFixes ? RememberChoice
: ForgetChoice);
allowFixes ? RememberChoice
: ForgetChoice);
}

ConstraintSystem::SolutionKind
Expand Down
4 changes: 0 additions & 4 deletions lib/Sema/Constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,10 +612,6 @@ Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
assert((kind != ConstraintKind::LiteralConformsTo) ||
second->is<ProtocolType>());

// Bridging constraints require bridging to be enabled.
assert(kind != ConstraintKind::BridgingConversion
|| cs.TC.Context.LangOpts.EnableObjCInterop);

// Create the constraint.
unsigned size = totalSizeToAlloc<TypeVariableType*>(typeVars.size());
void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
Expand Down
8 changes: 3 additions & 5 deletions lib/Sema/TypeCheckConstraints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2878,8 +2878,7 @@ bool TypeChecker::isExplicitlyConvertibleTo(Type type1, Type type2,

bool TypeChecker::isObjCBridgedTo(Type type1, Type type2, DeclContext *dc,
bool *unwrappedIUO) {
return (Context.LangOpts.EnableObjCInterop &&
typesSatisfyConstraint(type1, type2,
return (typesSatisfyConstraint(type1, type2,
/*openArchetypes=*/false,
ConstraintKind::BridgingConversion,
dc, unwrappedIUO));
Expand Down Expand Up @@ -3391,9 +3390,8 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
}

// Check for a bridging conversion.
// Anything bridges to AnyObject in ObjC interop mode.
if (Context.LangOpts.EnableObjCInterop
&& toType->isAnyObject())
// Anything bridges to AnyObject.
if (toType->isAnyObject())
return CheckedCastKind::BridgingCoercion;

// Do this check later in Swift 3 mode so that we check for NSNumber and
Expand Down
182 changes: 181 additions & 1 deletion stdlib/public/core/BridgeObjectiveC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//
//===----------------------------------------------------------------------===//

#if _runtime(_ObjC)
/// A Swift Array or Dictionary of types conforming to
/// `_ObjectiveCBridgeable` can be passed to Objective-C as an NSArray or
/// NSDictionary, respectively. The elements of the resulting NSArray
Expand Down Expand Up @@ -83,6 +82,8 @@ public protocol _ObjectiveCBridgeable {
-> Self
}

#if _runtime(_ObjC)

//===--- Bridging for metatypes -------------------------------------------===//

/// A stand-in for a value of metatype type.
Expand Down Expand Up @@ -640,3 +641,182 @@ public func _getObjCTypeEncoding<T>(_ type: T.Type) -> UnsafePointer<Int8> {
}

#endif

//===--- Bridging without the ObjC runtime --------------------------------===//

#if !_runtime(_ObjC)

/// Convert `x` from its Objective-C representation to its Swift
/// representation.
/// COMPILER_INTRINSIC
@_inlineable // FIXME(sil-serialize-all)
public func _forceBridgeFromObjectiveC_bridgeable<T:_ObjectiveCBridgeable> (
_ x: T._ObjectiveCType,
_: T.Type
) -> T {
var result: T?
T._forceBridgeFromObjectiveC(x, result: &result)
return result!
}

/// Attempt to convert `x` from its Objective-C representation to its Swift
/// representation.
/// COMPILER_INTRINSIC
@_inlineable // FIXME(sil-serialize-all)
public func _conditionallyBridgeFromObjectiveC_bridgeable<T:_ObjectiveCBridgeable>(
_ x: T._ObjectiveCType,
_: T.Type
) -> T? {
var result: T?
T._conditionallyBridgeFromObjectiveC (x, result: &result)
return result
}

public // SPI(Foundation)
protocol _NSSwiftValue: class {
init(_ value: Any)
var value: Any { get }
static var null: AnyObject { get }
}

@usableFromInline
internal class _SwiftValue {
@usableFromInline
let value: Any

@usableFromInline
init(_ value: Any) {
self.value = value
}

@usableFromInline
static let null = _SwiftValue(Optional<Any>.none as Any)
}

// Internal stdlib SPI
@_silgen_name("swift_unboxFromSwiftValueWithType")
public func swift_unboxFromSwiftValueWithType<T>(
_ source: inout AnyObject,
_ result: UnsafeMutablePointer<T>
) -> Bool {

if source === _nullPlaceholder {
if let unpacked = Optional<Any>.none as? T {
result.initialize(to: unpacked)
return true
}
}

if let box = source as? _SwiftValue {
if let value = box.value as? T {
result.initialize(to: value)
return true
}
} else if let box = source as? _NSSwiftValue {
if let value = box.value as? T {
result.initialize(to: value)
return true
}
}

return false
}

// Internal stdlib SPI
@_silgen_name("swift_swiftValueConformsTo")
public func _swiftValueConformsTo<T>(_ type: T.Type) -> Bool {
if let foundationType = _foundationSwiftValueType {
return foundationType is T.Type
} else {
return _SwiftValue.self is T.Type
}
}

@_silgen_name("_swift_extractDynamicValue")
public func _extractDynamicValue<T>(_ value: T) -> AnyObject?

@_silgen_name("_swift_bridgeToObjectiveCUsingProtocolIfPossible")
public func _bridgeToObjectiveCUsingProtocolIfPossible<T>(_ value: T) -> AnyObject?

@usableFromInline
protocol _Unwrappable {
func unwrap() -> Any?
}

extension Optional: _Unwrappable {
func unwrap() -> Any? {
return self
}
}

private let _foundationSwiftValueType = _typeByName("Foundation._SwiftValue") as? _NSSwiftValue.Type

@usableFromInline
internal var _nullPlaceholder: AnyObject {
if let foundationType = _foundationSwiftValueType {
return foundationType.null
} else {
return _SwiftValue.null
}
}

@usableFromInline
func _makeSwiftValue(_ value: Any) -> AnyObject {
if let foundationType = _foundationSwiftValueType {
return foundationType.init(value)
} else {
return _SwiftValue(value)
}
}

/// Bridge an arbitrary value to an Objective-C object.
///
/// - If `T` is a class type, it is always bridged verbatim, the function
/// returns `x`;
///
/// - otherwise, if `T` conforms to `_ObjectiveCBridgeable`,
/// returns the result of `x._bridgeToObjectiveC()`;
///
/// - otherwise, we use **boxing** to bring the value into Objective-C.
/// The value is wrapped in an instance of a private Objective-C class
/// that is `id`-compatible and dynamically castable back to the type of
/// the boxed value, but is otherwise opaque.
///
/// COMPILER_INTRINSIC
@inlinable // FIXME(sil-serialize-all)
public func _bridgeAnythingToObjectiveC<T>(_ x: T) -> AnyObject {
var done = false
var result: AnyObject!

var source: Any = x

if let dynamicSource = _extractDynamicValue(x) {
result = dynamicSource as AnyObject
done = true
}

if !done, let wrapper = source as? _Unwrappable {
if let value = wrapper.unwrap() {
result = value as AnyObject
} else {
result = _nullPlaceholder
}

done = true
}

if !done {
if type(of: source) as? AnyClass != nil {
result = unsafeBitCast(x, to: AnyObject.self)
} else if let object = _bridgeToObjectiveCUsingProtocolIfPossible(source) {
result = object
} else {
result = _makeSwiftValue(source)
}
}

return result
}

#endif // !_runtime(_ObjC)

4 changes: 2 additions & 2 deletions stdlib/public/core/Codable.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1180,7 +1180,7 @@ public enum EncodingError : Error {
public var _userInfo: AnyObject? {
// The error dictionary must be returned as an AnyObject. We can do this
// only on platforms with bridging, unfortunately.
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#if _runtime(_ObjC)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could actually remove this #if now, right? We should be able to return [String : Any] as AnyObject on all platforms, yeah?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, yeah :)

let context: Context
switch self {
case .invalidValue(_, let c): context = c
Expand Down Expand Up @@ -1290,7 +1290,7 @@ public enum DecodingError : Error {
public var _userInfo: AnyObject? {
// The error dictionary must be returned as an AnyObject. We can do this
// only on platforms with bridging, unfortunately.
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#if _runtime(_ObjC)
let context: Context
switch self {
case .keyNotFound(_, let c): context = c
Expand Down
Loading