Skip to content

Commit 46bc50d

Browse files
authored
Merge pull request #28827 from DougGregor/type-checker-cast-nserror
2 parents a8f2f95 + 942aeca commit 46bc50d

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4453,11 +4453,13 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
44534453
// type. This is handled in the runtime, so it doesn't need a special cast
44544454
// kind.
44554455
if (Context.LangOpts.EnableObjCInterop) {
4456+
auto nsObject = Context.getNSObjectType();
4457+
auto nsErrorTy = Context.getNSErrorType();
4458+
44564459
if (auto errorTypeProto = Context.getProtocol(KnownProtocolKind::Error)) {
44574460
if (!conformsToProtocol(toType, errorTypeProto, dc,
44584461
ConformanceCheckFlags::InExpression)
44594462
.isInvalid()) {
4460-
auto nsErrorTy = Context.getNSErrorType();
44614463
if (nsErrorTy) {
44624464
if (isSubtypeOf(fromType, nsErrorTy, dc)
44634465
// Don't mask "always true" warnings if NSError is cast to
@@ -4466,6 +4468,23 @@ CheckedCastKind TypeChecker::typeCheckCheckedCast(Type fromType,
44664468
return CheckedCastKind::ValueCast;
44674469
}
44684470
}
4471+
4472+
if (!conformsToProtocol(fromType, errorTypeProto, dc,
4473+
ConformanceCheckFlags::InExpression)
4474+
.isInvalid()) {
4475+
// Cast of an error-conforming type to NSError or NSObject.
4476+
if ((nsObject && toType->isEqual(nsObject)) ||
4477+
(nsErrorTy && toType->isEqual(nsErrorTy)))
4478+
return CheckedCastKind::BridgingCoercion;
4479+
}
4480+
}
4481+
4482+
// Any class-like type could be dynamically cast to NSObject or NSError
4483+
// via an Error conformance.
4484+
if (fromType->mayHaveSuperclass() &&
4485+
((nsObject && toType->isEqual(nsObject)) ||
4486+
(nsErrorTy && toType->isEqual(nsErrorTy)))) {
4487+
return CheckedCastKind::ValueCast;
44694488
}
44704489
}
44714490

test/Constraints/ErrorBridging.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,24 @@ extension Error {
7373
func throwErrorCode() throws {
7474
throw FictionalServerError.meltedDown // expected-error{{thrown error code type 'FictionalServerError.Code' does not conform to 'Error'; construct an 'FictionalServerError' instance}}{{29-29=(}}{{40-40=)}}
7575
}
76+
77+
class MyErrorClass { }
78+
extension MyErrorClass: Error { }
79+
80+
class MyClass { }
81+
82+
func testUnknownErrorBridge(cond: Bool, mc: MyClass) -> NSObject? {
83+
if cond {
84+
return mc as? NSError // okay
85+
}
86+
87+
return mc as? NSObject // okay
88+
}
89+
90+
func testAlwaysErrorBridge(cond: Bool, mec: MyErrorClass) -> NSObject? {
91+
if cond {
92+
return mec as? NSError // expected-warning{{conditional cast from 'MyErrorClass}}' to 'NSError' always succeeds
93+
}
94+
95+
return mec as? NSObject // expected-warning{{conditional cast from 'MyErrorClass}}' to 'NSObject' always succeeds
96+
}

0 commit comments

Comments
 (0)