Skip to content

Commit 3bc1c78

Browse files
authored
Merge pull request #3680 from jckarter/explicit-anyobject-conversion
2 parents 46c1f1e + 27a4a8f commit 3bc1c78

File tree

4 files changed

+86
-18
lines changed

4 files changed

+86
-18
lines changed

lib/AST/Type.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,11 +1986,11 @@ static ForeignRepresentableKind
19861986
getObjCObjectRepresentable(Type type, const DeclContext *dc) {
19871987
// @objc metatypes are representable when their instance type is.
19881988
if (auto metatype = type->getAs<AnyMetatypeType>()) {
1989-
// If the instance type is not representable, the metatype is not
1989+
// If the instance type is not representable verbatim, the metatype is not
19901990
// representable.
19911991
auto instanceType = metatype->getInstanceType();
19921992
if (getObjCObjectRepresentable(instanceType, dc)
1993-
== ForeignRepresentableKind::None)
1993+
!= ForeignRepresentableKind::Object)
19941994
return ForeignRepresentableKind::None;
19951995

19961996
// Objective-C metatypes are trivially representable.

lib/Sema/CSApply.cpp

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1424,6 +1424,10 @@ namespace {
14241424
///
14251425
/// \param value The value to be bridged.
14261426
Expr *bridgeToObjectiveC(Expr *value) {
1427+
// TODO: It would be nicer to represent this as a special AST node
1428+
// instead of inlining the bridging calls in the AST. Doing so would
1429+
// simplify the AST and make it easier for SILGen to peephole bridging
1430+
// conversions.
14271431
auto &tc = cs.getTypeChecker();
14281432

14291433
// Find the _ObjectiveCBridgeable protocol.
@@ -1433,25 +1437,45 @@ namespace {
14331437
// Find the conformance of the value type to _ObjectiveCBridgeable.
14341438
ProtocolConformance *conformance = nullptr;
14351439
Type valueType = value->getType()->getRValueType();
1436-
bool conforms =
1440+
bool conformsToBridgeable =
14371441
tc.conformsToProtocol(valueType, bridgedProto, cs.DC,
14381442
(ConformanceCheckFlags::InExpression|
14391443
ConformanceCheckFlags::Used),
14401444
&conformance);
14411445

1442-
// If there is no _ObjectiveCBridgeable conformance, treat this
1443-
// as bridging an error.
1444-
if (!conforms)
1446+
if (conformsToBridgeable) {
1447+
// Form the call.
1448+
return tc.callWitness(value, cs.DC, bridgedProto,
1449+
conformance,
1450+
tc.Context.Id_bridgeToObjectiveC,
1451+
{ }, diag::broken_bridged_to_objc_protocol);
1452+
}
1453+
1454+
// If there is an Error conformance, try bridging as an error.
1455+
if (tc.isConvertibleTo(valueType,
1456+
tc.Context.getProtocol(KnownProtocolKind::Error)
1457+
->getDeclaredType(),
1458+
cs.DC))
14451459
return bridgeErrorToObjectiveC(value);
14461460

1447-
assert(conforms && "Should already have checked the conformance");
1448-
(void)conforms;
1449-
1450-
// Form the call.
1451-
return tc.callWitness(value, cs.DC, bridgedProto,
1452-
conformance,
1453-
tc.Context.Id_bridgeToObjectiveC,
1454-
{ }, diag::broken_bridged_to_objc_protocol);
1461+
// Fall back to universal bridging.
1462+
auto bridgeAnything = tc.Context.getBridgeAnythingToObjectiveC(&tc);
1463+
value = tc.coerceToRValue(value);
1464+
auto valueSub = Substitution(valueType, {});
1465+
auto bridgeAnythingRef = ConcreteDeclRef(tc.Context, bridgeAnything,
1466+
valueSub);
1467+
auto bridgeTy = tc.Context.getProtocol(KnownProtocolKind::AnyObject)
1468+
->getDeclaredType();
1469+
auto bridgeFnTy = FunctionType::get(valueType, bridgeTy);
1470+
auto fnRef = new (tc.Context) DeclRefExpr(bridgeAnythingRef,
1471+
DeclNameLoc(),
1472+
/*implicit*/ true,
1473+
AccessSemantics::Ordinary,
1474+
bridgeFnTy);
1475+
Expr *call = new (tc.Context) CallExpr(fnRef, value,
1476+
/*implicit*/ true,
1477+
bridgeTy);
1478+
return call;
14551479
}
14561480

14571481
/// Bridge the given object from Objective-C to its value type.

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,17 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
16931693
}
16941694

16951695
if (kind == TypeMatchKind::ExplicitConversion) {
1696+
// Anything can be explicitly converted to AnyObject using the universal
1697+
// bridging conversion.
1698+
if (auto protoType2 = type2->getAs<ProtocolType>()) {
1699+
if (TC.Context.LangOpts.EnableIdAsAny
1700+
&& protoType2->getDecl()
1701+
== TC.Context.getProtocol(KnownProtocolKind::AnyObject)
1702+
&& !type1->mayHaveSuperclass()
1703+
&& !type1->isClassExistentialType())
1704+
conversionsOrFixes.push_back(ConversionRestrictionKind::BridgeToObjC);
1705+
}
1706+
16961707
// Bridging from an Objective-C class type to a value type.
16971708
// Note that specifically require a class or class-constrained archetype
16981709
// here, because archetypes cannot be bridged.
@@ -4035,7 +4046,15 @@ ConstraintSystem::simplifyRestrictedConstraint(ConversionRestrictionKind restric
40354046
// T bridges to C and C < U ===> T <c U
40364047
case ConversionRestrictionKind::BridgeToObjC: {
40374048
auto objcClass = TC.getBridgedToObjC(DC, type1);
4038-
assert(objcClass && "type is not bridged to Objective-C?");
4049+
// If the type doesn't bridge any other way, we can still go straight to
4050+
// AnyObject by universal bridging.
4051+
if (!objcClass) {
4052+
assert(TC.Context.LangOpts.EnableIdAsAny
4053+
&& "should only happen in id-as-any mode");
4054+
objcClass = TC.Context.getProtocol(KnownProtocolKind::AnyObject)
4055+
->getDeclaredType();
4056+
}
4057+
40394058
addContextualScore();
40404059
increaseScore(SK_UserConversion); // FIXME: Use separate score kind?
40414060
if (worseThanBestSolution()) {

test/Constraints/bridging.swift

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// RUN: %target-parse-verify-swift
1+
// RUN: %target-swift-frontend -parse -verify %s -enable-id-as-any
22

33
// REQUIRES: objc_interop
44

55
import Foundation
66

77
public class BridgedClass : NSObject, NSCopying {
88
@objc(copyWithZone:)
9-
public func copy(with zone: NSZone?) -> AnyObject {
9+
public func copy(with zone: NSZone?) -> Any {
1010
return self
1111
}
1212
}
@@ -325,4 +325,29 @@ func forceBridgeDiag(_ obj: BridgedClass!) -> BridgedStruct {
325325
return obj // expected-error{{'BridgedClass!' is not implicitly convertible to 'BridgedStruct'; did you mean to use 'as' to explicitly convert?}}{{13-13= as BridgedStruct}}
326326
}
327327

328-
328+
struct KnownUnbridged {}
329+
class KnownClass {}
330+
protocol KnownClassProtocol: class {}
331+
332+
func forceUniversalBridgeToAnyObject<T, U: KnownClassProtocol>(a: T, b: U, c: Any, d: KnownUnbridged, e: KnownClass, f: KnownClassProtocol, g: AnyObject, h: String) {
333+
var z: AnyObject
334+
z = a as AnyObject
335+
z = b as AnyObject
336+
z = c as AnyObject
337+
z = d as AnyObject
338+
z = e as AnyObject
339+
z = f as AnyObject
340+
z = g as AnyObject
341+
z = h as AnyObject
342+
343+
z = a // expected-error{{does not conform to 'AnyObject'}}
344+
z = b
345+
z = c // expected-error{{does not conform to 'AnyObject'}}
346+
z = d // expected-error{{does not conform to 'AnyObject'}}
347+
z = e
348+
z = f
349+
z = g
350+
z = h // todo{{does not conform to 'AnyObject'}}
351+
352+
_ = z
353+
}

0 commit comments

Comments
 (0)