Skip to content

Commit 78e9eb5

Browse files
authored
Merge pull request #13995 from rudkx/fix-iuo-bridging-swift-5.0-branch
Fix IUO bridging swift 5.0 branch
2 parents 16e2d85 + 7722286 commit 78e9eb5

File tree

3 files changed

+102
-83
lines changed

3 files changed

+102
-83
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 21 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,11 @@ namespace {
133133
};
134134
} // end anonymous namespace
135135

136-
static std::tuple<Type, Type, OptionalAdjustmentKind>
137-
getTypesToCompare(ValueDecl *reqt, Type reqtType, bool reqtTypeIsIUO,
138-
Type witnessType, bool witnessTypeIsIUO,
139-
VarianceKind variance) {
136+
static std::tuple<Type,Type, OptionalAdjustmentKind>
137+
getTypesToCompare(ValueDecl *reqt,
138+
Type reqtType,
139+
Type witnessType,
140+
VarianceKind variance) {
140141
// For @objc protocols, deal with differences in the optionality.
141142
// FIXME: It probably makes sense to extend this to non-@objc
142143
// protocols as well, but this requires more testing.
@@ -159,11 +160,6 @@ getTypesToCompare(ValueDecl *reqt, Type reqtType, bool reqtTypeIsIUO,
159160
break;
160161

161162
case OTK_Optional:
162-
if (witnessTypeIsIUO) {
163-
optAdjustment = OptionalAdjustmentKind::RemoveIUO;
164-
break;
165-
}
166-
167163
switch (variance) {
168164
case VarianceKind::None:
169165
case VarianceKind::Covariant:
@@ -183,17 +179,6 @@ getTypesToCompare(ValueDecl *reqt, Type reqtType, bool reqtTypeIsIUO,
183179
break;
184180

185181
case OTK_Optional:
186-
// When the requirement is an IUO, all is permitted, because we
187-
// assume that the user knows more about the signature than we
188-
// have information in the protocol.
189-
if (reqtTypeIsIUO)
190-
break;
191-
192-
if (witnessTypeIsIUO) {
193-
optAdjustment = OptionalAdjustmentKind::IUOToOptional;
194-
break;
195-
}
196-
197182
switch (witnessOptKind) {
198183
case OTK_None:
199184
switch (variance) {
@@ -224,15 +209,6 @@ getTypesToCompare(ValueDecl *reqt, Type reqtType, bool reqtTypeIsIUO,
224209
// have information in the protocol.
225210
break;
226211
}
227-
} else {
228-
// FIXME: Until IUOs are removed from the type system, make
229-
// sure we turn these both into optionals for the purpose of
230-
// comparing types since we could be producing IUOs in some
231-
// places and optionals in others.
232-
if (auto objTy = reqtType->getImplicitlyUnwrappedOptionalObjectType())
233-
reqtType = OptionalType::get(objTy);
234-
if (auto objTy = witnessType->getImplicitlyUnwrappedOptionalObjectType())
235-
witnessType = OptionalType::get(objTy);
236212
}
237213

238214
return std::make_tuple(reqtType, witnessType, optAdjustment);
@@ -368,14 +344,6 @@ static bool checkObjCWitnessSelector(TypeChecker &tc, ValueDecl *req,
368344
return false;
369345
}
370346

371-
static ParameterList *getParameterList(ValueDecl *value) {
372-
if (auto func = dyn_cast<AbstractFunctionDecl>(value))
373-
return func->getParameterList(func->getDeclContext()->isTypeContext());
374-
375-
auto subscript = cast<SubscriptDecl>(value);
376-
return subscript->getIndices();
377-
}
378-
379347
RequirementMatch
380348
swift::matchWitness(
381349
TypeChecker &tc,
@@ -523,24 +491,18 @@ swift::matchWitness(
523491
// Result types must match.
524492
// FIXME: Could allow (trivial?) subtyping here.
525493
if (!ignoreReturnType) {
526-
auto reqTypeIsIUO =
527-
req->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
528-
auto witnessTypeIsIUO =
529-
witness->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
530-
auto types =
531-
getTypesToCompare(req, reqResultType, reqTypeIsIUO, witnessResultType,
532-
witnessTypeIsIUO, VarianceKind::Covariant);
494+
auto types = getTypesToCompare(req, reqResultType,
495+
witnessResultType,
496+
VarianceKind::Covariant);
533497

534498
// Record optional adjustment, if any.
535499
if (std::get<2>(types) != OptionalAdjustmentKind::None) {
536500
optionalAdjustments.push_back(
537501
OptionalAdjustment(std::get<2>(types)));
538502
}
539503

540-
if (!req->isObjC() && reqTypeIsIUO != witnessTypeIsIUO)
541-
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
542-
543-
if (auto result = matchTypes(std::get<0>(types), std::get<1>(types))) {
504+
if (auto result = matchTypes(std::get<0>(types),
505+
std::get<1>(types))) {
544506
return std::move(result.getValue());
545507
}
546508
}
@@ -556,12 +518,6 @@ swift::matchWitness(
556518
return RequirementMatch(witness, MatchKind::TypeConflict,
557519
witnessType);
558520

559-
ParameterList *witnessParamList = getParameterList(witness);
560-
assert(witnessParamList->size() == witnessParams.size());
561-
562-
ParameterList *reqParamList = getParameterList(req);
563-
assert(reqParamList->size() == reqParams.size());
564-
565521
// Match each of the parameters.
566522
for (unsigned i = 0, n = reqParams.size(); i != n; ++i) {
567523
// Variadic bits must match.
@@ -575,33 +531,21 @@ swift::matchWitness(
575531
if (reqParams[i].isInOut() != witnessParams[i].isInOut())
576532
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
577533

578-
auto reqParamDecl = reqParamList->get(i);
579-
auto witnessParamDecl = witnessParamList->get(i);
580-
581-
auto reqParamTypeIsIUO =
582-
reqParamDecl->getAttrs()
583-
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
584-
auto witnessParamTypeIsIUO =
585-
witnessParamDecl->getAttrs()
586-
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
587-
588534
// Gross hack: strip a level of unchecked-optionality off both
589535
// sides when matching against a protocol imported from Objective-C.
590-
auto types =
591-
getTypesToCompare(req, reqParams[i].getType(), reqParamTypeIsIUO,
592-
witnessParams[i].getType(), witnessParamTypeIsIUO,
593-
VarianceKind::Contravariant);
536+
auto types = getTypesToCompare(req, reqParams[i].getType(),
537+
witnessParams[i].getType(),
538+
VarianceKind::Contravariant);
594539

595540
// Record any optional adjustment that occurred.
596541
if (std::get<2>(types) != OptionalAdjustmentKind::None) {
597542
optionalAdjustments.push_back(
598543
OptionalAdjustment(std::get<2>(types), i));
599544
}
600545

601-
if (!req->isObjC() && reqParamTypeIsIUO != witnessParamTypeIsIUO)
602-
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
603-
604-
if (auto result = matchTypes(std::get<0>(types), std::get<1>(types))) {
546+
// Check whether the parameter types match.
547+
if (auto result = matchTypes(std::get<0>(types),
548+
std::get<1>(types))) {
605549
return std::move(result.getValue());
606550
}
607551
}
@@ -613,22 +557,16 @@ swift::matchWitness(
613557
}
614558

615559
} else {
616-
auto reqTypeIsIUO =
617-
req->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
618-
auto witnessTypeIsIUO =
619-
witness->getAttrs().hasAttribute<ImplicitlyUnwrappedOptionalAttr>();
620-
auto types = getTypesToCompare(req, reqType, reqTypeIsIUO, witnessType,
621-
witnessTypeIsIUO, VarianceKind::None);
560+
// Simple case: add the constraint.
561+
auto types = getTypesToCompare(req, reqType, witnessType,
562+
VarianceKind::None);
622563

623564
// Record optional adjustment, if any.
624565
if (std::get<2>(types) != OptionalAdjustmentKind::None) {
625566
optionalAdjustments.push_back(
626567
OptionalAdjustment(std::get<2>(types)));
627568
}
628569

629-
if (!req->isObjC() && reqTypeIsIUO != witnessTypeIsIUO)
630-
return RequirementMatch(witness, MatchKind::TypeConflict, witnessType);
631-
632570
if (auto result = matchTypes(std::get<0>(types), std::get<1>(types))) {
633571
return std::move(result.getValue());
634572
}
@@ -786,8 +724,8 @@ RequirementMatch swift::matchWitness(TypeChecker &tc,
786724
};
787725

788726
// Match a type in the requirement to a type in the witness.
789-
auto matchTypes = [&](Type reqType,
790-
Type witnessType) -> Optional<RequirementMatch> {
727+
auto matchTypes = [&](Type reqType, Type witnessType)
728+
-> Optional<RequirementMatch> {
791729
cs->addConstraint(ConstraintKind::Equal, reqType, witnessType, locator);
792730
// FIXME: Check whether this has already failed.
793731
return None;

stdlib/public/core/ImplicitlyUnwrappedOptional.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,48 @@ public enum ImplicitlyUnwrappedOptional<Wrapped> : ExpressibleByNilLiteral {
4949
self = .none
5050
}
5151
}
52+
53+
#if _runtime(_ObjC)
54+
extension ImplicitlyUnwrappedOptional : _ObjectiveCBridgeable {
55+
@_inlineable // FIXME(sil-serialize-all)
56+
public func _bridgeToObjectiveC() -> AnyObject {
57+
switch self {
58+
case .none:
59+
_preconditionFailure("Attempt to bridge an implicitly unwrapped optional containing nil")
60+
61+
case .some(let x):
62+
return Swift._bridgeAnythingToObjectiveC(x)
63+
}
64+
}
65+
66+
@_inlineable // FIXME(sil-serialize-all)
67+
public static func _forceBridgeFromObjectiveC(
68+
_ x: AnyObject,
69+
result: inout ImplicitlyUnwrappedOptional<Wrapped>?
70+
) {
71+
result = Swift._forceBridgeFromObjectiveC(x, Wrapped.self)
72+
}
73+
74+
@_inlineable // FIXME(sil-serialize-all)
75+
public static func _conditionallyBridgeFromObjectiveC(
76+
_ x: AnyObject,
77+
result: inout ImplicitlyUnwrappedOptional<Wrapped>?
78+
) -> Bool {
79+
let bridged: Wrapped? =
80+
Swift._conditionallyBridgeFromObjectiveC(x, Wrapped.self)
81+
if let value = bridged {
82+
result = value
83+
}
84+
85+
return false
86+
}
87+
88+
@_inlineable // FIXME(sil-serialize-all)
89+
public static func _unconditionallyBridgeFromObjectiveC(_ source: AnyObject?)
90+
-> Wrapped! {
91+
var result: ImplicitlyUnwrappedOptional<Wrapped>?
92+
_forceBridgeFromObjectiveC(source!, result: &result)
93+
return result!
94+
}
95+
}
96+
#endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %target-run-simple-swift | %FileCheck %s
2+
// REQUIRES: executable_test
3+
// REQUIRES: objc_interop
4+
5+
import Foundation
6+
7+
// rdar://problem/36477954
8+
func AnyToNSObject(_ a: Any) {
9+
if a is NSObject {
10+
// ok
11+
} else {
12+
fatalError("argument is not bridgable to NSObject")
13+
}
14+
}
15+
16+
let opt: String? = "hello"
17+
AnyToNSObject(opt as Any)
18+
19+
let doubleOpt: String?? = "hello"
20+
AnyToNSObject(doubleOpt as Any)
21+
22+
let iuo: String! = "goodbye"
23+
AnyToNSObject(iuo as Any)
24+
25+
let doubleIUO: String!! = "goodbye"
26+
AnyToNSObject(doubleIUO as Any)
27+
28+
// rdar://problem/36559165
29+
let dict = NSMutableDictionary()
30+
let kSomeKey: String! = "kSomeKey"
31+
dict.setValue(true as Any, forKey: kSomeKey)
32+
// CHECK: value: 1
33+
print("value:", dict[kSomeKey] ?? "nil")
34+
35+
// CHECK: ok
36+
print("ok")

0 commit comments

Comments
 (0)