Skip to content

Commit 6575877

Browse files
committed
[@objc checking] Only 'Error' is representable in Objective-C (as 'NSError').
Don't allow types conforming to 'Error' or protocol compositions involving 'Error' to be reflected in Objective-C. We still allow bridging conversions, but they are not statically bridged. Fixes SR-2249/rdar://problem/27658940.
1 parent b43e1e7 commit 6575877

File tree

6 files changed

+34
-56
lines changed

6 files changed

+34
-56
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2750,6 +2750,8 @@ NOTE(not_objc_empty_protocol_composition,none,
27502750
"'Any' is not considered '@objc'; use 'AnyObject' instead", ())
27512751
NOTE(not_objc_protocol,none,
27522752
"protocol %0 is not '@objc'", (Type))
2753+
NOTE(not_objc_error_protocol_composition,none,
2754+
"protocol composition involving 'Error' is not '@objc'", ())
27532755
NOTE(not_objc_empty_tuple,none,
27542756
"empty tuple type cannot be represented in Objective-C", ())
27552757
NOTE(not_objc_tuple,none,

lib/AST/Type.cpp

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,33 +2189,8 @@ getForeignRepresentable(Type type, ForeignLanguage language,
21892189
if (type->isTypeParameter() && language == ForeignLanguage::ObjectiveC)
21902190
return { ForeignRepresentableKind::Object, nullptr };
21912191

2192-
// In Objective-C, existentials involving Error are bridged
2193-
// to NSError.
2194-
if (language == ForeignLanguage::ObjectiveC &&
2195-
type->isExistentialWithError()) {
2196-
return { ForeignRepresentableKind::BridgedError, nullptr };
2197-
}
2198-
2199-
/// Determine whether the given type is a type that is bridged to NSError
2200-
/// because it conforms to the Error protocol.
2201-
auto isBridgedErrorViaConformance = [dc](Type type) -> bool {
2202-
ASTContext &ctx = type->getASTContext();
2203-
auto errorProto = ctx.getProtocol(KnownProtocolKind::Error);
2204-
if (!errorProto) return false;
2205-
2206-
return dc->getParentModule()->lookupConformance(type, errorProto,
2207-
ctx.getLazyResolver())
2208-
.hasValue();
2209-
};
2210-
22112192
auto nominal = type->getAnyNominal();
2212-
if (!nominal) {
2213-
/// It might still be a bridged Error via conformance to Error.
2214-
if (isBridgedErrorViaConformance(type))
2215-
return { ForeignRepresentableKind::BridgedError, nullptr };
2216-
2217-
return failure();
2218-
}
2193+
if (!nominal) return failure();
22192194

22202195
ASTContext &ctx = nominal->getASTContext();
22212196

@@ -2300,13 +2275,7 @@ getForeignRepresentable(Type type, ForeignLanguage language,
23002275
// Determine whether this nominal type is known to be representable
23012276
// in this foreign language.
23022277
auto result = ctx.getForeignRepresentationInfo(nominal, language, dc);
2303-
if (result.getKind() == ForeignRepresentableKind::None) {
2304-
/// It might still be a bridged Error via conformance to Error.
2305-
if (isBridgedErrorViaConformance(type))
2306-
return { ForeignRepresentableKind::BridgedError, nullptr };
2307-
2308-
return failure();
2309-
}
2278+
if (result.getKind() == ForeignRepresentableKind::None) return failure();
23102279

23112280
if (wasOptional && !result.isRepresentableAsOptional())
23122281
return failure();

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,26 +1289,15 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
12891289
PCT = cast<ProtocolCompositionType>(canonicalComposition);
12901290

12911291
// Dig out the protocols. If we see 'Error', record that we saw it.
1292-
bool hasError = false;
12931292
SmallVector<ProtocolDecl *, 4> protos;
12941293
for (auto protoTy : PCT->getProtocols()) {
12951294
auto proto = protoTy->castTo<ProtocolType>()->getDecl();
1296-
if (proto->isSpecificProtocol(KnownProtocolKind::Error)) {
1297-
hasError = true;
1298-
continue;
1299-
}
1300-
13011295
protos.push_back(proto);
13021296
}
13031297

1304-
os << (isMetatype ? "Class"
1305-
: hasError ? "NSError"
1306-
: "id");
1298+
os << (isMetatype ? "Class" : "id");
13071299
printProtocols(protos);
13081300

1309-
if (hasError && !isMetatype)
1310-
os << " *";
1311-
13121301
printNullability(optionalKind);
13131302
}
13141303

@@ -1823,10 +1812,9 @@ class ModuleWriter {
18231812

18241813
ASTContext &ctx = M.getASTContext();
18251814

1826-
auto protos = ED->getAllProtocols();
1815+
SmallVector<ProtocolConformance *, 1> conformances;
18271816
auto errorTypeProto = ctx.getProtocol(KnownProtocolKind::Error);
1828-
if (std::find(protos.begin(), protos.end(), errorTypeProto) !=
1829-
protos.end()) {
1817+
if (ED->lookupConformance(&M, errorTypeProto, conformances)) {
18301818
bool hasDomainCase = std::any_of(ED->getAllElements().begin(),
18311819
ED->getAllElements().end(),
18321820
[](const EnumElementDecl *elem) {

lib/Sema/TypeCheckType.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3237,13 +3237,25 @@ void TypeChecker::diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
32373237
return;
32383238
}
32393239
// Find a protocol that is not @objc.
3240+
bool sawErrorProtocol = false;
32403241
for (auto PD : Protocols) {
3242+
if (PD->isSpecificProtocol(KnownProtocolKind::Error)) {
3243+
sawErrorProtocol = true;
3244+
break;
3245+
}
3246+
32413247
if (!PD->isObjC()) {
32423248
diagnose(TypeRange.Start, diag::not_objc_protocol,
32433249
PD->getDeclaredType());
32443250
return;
32453251
}
32463252
}
3253+
3254+
if (sawErrorProtocol) {
3255+
diagnose(TypeRange.Start, diag::not_objc_error_protocol_composition);
3256+
return;
3257+
}
3258+
32473259
return;
32483260
}
32493261

test/PrintAsObjC/error-delegate.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,12 @@
1818

1919
import Foundation
2020

21-
@objc protocol MySwiftProtocol { }
22-
2321
// CHECK-LABEL: @interface Test : NSObject <ABCErrorProtocol>
2422
// CHECK-NEXT: - (void)didFail:(NSError * _Nonnull)error;
2523
// CHECK-NEXT: - (void)didFailOptional:(NSError * _Nullable)error;
26-
// CHECK-NEXT-FIXME: - (void)composition:(NSError<MySwiftProtocol> * _Nonnull)error;
27-
// CHECK-NEXT-FIXME: - (void)compositionOptional:(NSError<MySwiftProtocol> * _Nullable)error;
2824
// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
2925
// CHECK-NEXT: @end
3026
class Test : NSObject, ABCErrorProtocol {
3127
func didFail(_ error: Swift.Error) {}
3228
func didFailOptional(_ error: Swift.Error?) {}
33-
34-
// FIXME: SILGenc crashes on this.
35-
// func composition(_ error: MySwiftProtocol & Error) { }
36-
// func compositionOptional(_ error: (MySwiftProtocol & Error)?) { }
3729
}

test/attr/attr_objc.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct PlainStruct {}
1111
enum PlainEnum {}
1212
protocol PlainProtocol {} // expected-note {{protocol 'PlainProtocol' declared here}}
1313

14+
enum ErrorEnum : Error { }
1415

1516
@objc class Class_ObjC1 {}
1617

@@ -1932,6 +1933,20 @@ class ClassThrows1 {
19321933
@objc init?(radians: Double) throws { } // expected-error{{a failable and throwing initializer cannot be marked @objc because 'nil' indicates failure to Objective-C}}
19331934

19341935
@objc init!(string: String) throws { } // expected-error{{a failable and throwing initializer cannot be marked @objc because 'nil' indicates failure to Objective-C}}
1936+
1937+
@objc func fooWithErrorEnum1(x: ErrorEnum) {}
1938+
// expected-error@-1{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
1939+
// expected-note@-2{{non-'@objc' enums cannot be represented in Objective-C}}
1940+
1941+
// CHECK: {{^}} func fooWithErrorEnum2(x: ErrorEnum)
1942+
func fooWithErrorEnum2(x: ErrorEnum) {}
1943+
1944+
@objc func fooWithErrorProtocolComposition1(x: Error & Protocol_ObjC1) { }
1945+
// expected-error@-1{{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
1946+
// expected-note@-2{{protocol composition involving 'Error' is not '@objc'}}
1947+
1948+
// CHECK: {{^}} func fooWithErrorProtocolComposition2(x: Error & Protocol_ObjC1)
1949+
func fooWithErrorProtocolComposition2(x: Error & Protocol_ObjC1) { }
19351950
}
19361951

19371952

0 commit comments

Comments
 (0)