Skip to content

Commit 9857464

Browse files
authored
Merge pull request #59334 from gottesmm/pr-499eee4e1aca5a8f3f38d1aeb7507c6e761eccd7
[silgen] Teach SILGen how to handle a corner case where the clang importer is improperly importing a method with a non-null NSError as throwing
2 parents 60860c2 + 71179c0 commit 9857464

File tree

7 files changed

+79
-4
lines changed

7 files changed

+79
-4
lines changed

include/swift/AST/Type.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ class CanType : public Type {
419419
static bool isObjCExistentialTypeImpl(CanType type);
420420
static bool isTypeErasedGenericClassTypeImpl(CanType type);
421421
static CanType getOptionalObjectTypeImpl(CanType type);
422+
static CanType wrapInOptionalTypeImpl(CanType type);
422423
static CanType getReferenceStorageReferentImpl(CanType type);
423424
static CanType getWithoutSpecifierTypeImpl(CanType type);
424425

@@ -523,6 +524,13 @@ class CanType : public Type {
523524

524525
bool isForeignReferenceType(); // in Types.h
525526

527+
/// Return this type wrapped into an Optional type. E.x.: 'T' ->
528+
/// 'Optional<T>'.
529+
CanType wrapInOptionalType() const {
530+
return wrapInOptionalTypeImpl(*this);
531+
}
532+
533+
/// If this is a type Optional<T>, return T. Otherwise return CanType().
526534
CanType getOptionalObjectType() const {
527535
return getOptionalObjectTypeImpl(*this);
528536
}

include/swift/AST/Types.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,6 +1232,9 @@ class alignas(1 << TypeAlignInBits) TypeBase
12321232
const ValueDecl *derivedDecl,
12331233
Type memberType);
12341234

1235+
/// If this type is T, return Optional<T>.
1236+
Type wrapInOptionalType() const;
1237+
12351238
/// Return T if this type is Optional<T>; otherwise, return the null type.
12361239
Type getOptionalObjectType();
12371240

lib/AST/Type.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,17 @@ CanType CanType::getOptionalObjectTypeImpl(CanType type) {
798798
return CanType();
799799
}
800800

801+
Type TypeBase::wrapInOptionalType() const {
802+
auto &ctx = getASTContext();
803+
auto *result = BoundGenericEnumType::get(ctx.getOptionalDecl(), Type(),
804+
{ getCanonicalType() });
805+
return result;
806+
}
807+
808+
CanType CanType::wrapInOptionalTypeImpl(CanType type) {
809+
return type->wrapInOptionalType()->getCanonicalType();
810+
}
811+
801812
Type TypeBase::getAnyPointerElementType(PointerTypeKind &PTK) {
802813
auto &C = getASTContext();
803814
if (isUnsafeMutableRawPointer()) {

lib/SIL/IR/SILType.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,8 @@ SILType SILType::getBuiltinWordType(const ASTContext &C) {
8888
}
8989

9090
SILType SILType::getOptionalType(SILType type) {
91-
auto &ctx = type.getASTContext();
92-
auto optType = BoundGenericEnumType::get(ctx.getOptionalDecl(), Type(),
93-
{ type.getASTType() });
94-
return getPrimitiveType(CanType(optType), type.getCategory())
91+
return getPrimitiveType(type.getASTType().wrapInOptionalType(),
92+
type.getCategory())
9593
.copyingMoveOnlyWrapper(type);
9694
}
9795

lib/SILGen/ResultPlan.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,23 @@ class ForeignErrorInitializationPlan final : public ResultPlan {
758758

759759
auto errorType =
760760
CanType(unwrappedPtrType->getAnyPointerElementType(ptrKind));
761+
762+
// In cases when from swift, we call objc imported methods written like so:
763+
//
764+
// (1) - (BOOL)submit:(NSError *_Nonnull __autoreleasing *_Nullable)errorOut;
765+
//
766+
// the clang importer will successfully import the given method as having a
767+
// non-null NSError. This doesn't follow the normal convention where we
768+
// expect the NSError to be Optional<NSError>. In order to preserve source
769+
// compatibility, we want to allow SILGen to handle this behavior. Luckily
770+
// in this case, NSError and Optional<NSError> are layout compatible, so we
771+
// can just pass in the Optional<NSError> and everything works.
772+
if (auto nsErrorTy = SGF.getASTContext().getNSErrorType()->getCanonicalType()) {
773+
if (errorType == nsErrorTy) {
774+
errorType = errorType.wrapInOptionalType();
775+
}
776+
}
777+
761778
auto &errorTL = SGF.getTypeLowering(errorType);
762779

763780
// Allocate a temporary.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@import Foundation;
2+
3+
@interface MyClass : NSObject {
4+
}
5+
6+
- (BOOL)submit:(NSError *_Nonnull __autoreleasing *_Nullable)errorOut;
7+
8+
@end
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %target-swift-frontend -enable-objc-interop -import-objc-header %S/Inputs/throwing-mismarked-nonnullable-error.h %s -emit-sil | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
// Make sure that we do not crash when importing a non-null NSError as
6+
// throwing. We really just shouldn't expect this at all. I filed: rdar://94656178
7+
// to track that work.
8+
9+
// CHECK-LABEL: sil hidden @$s4main1fyyF : $@convention(thin) () -> () {
10+
// CHECK: [[STACK:%.*]] = alloc_stack [dynamic_lifetime] $Optional<NSError>
11+
// CHECK: inject_enum_addr [[STACK]] : $*Optional<NSError>, #Optional.none!enumelt
12+
// CHECK: [[FN:%.*]] = objc_method {{%[0-9]+}} : $MyClass, #MyClass.submit!foreign : (MyClass) -> () throws -> (), $@convention(objc_method) (Optional<AutoreleasingUnsafeMutablePointer<NSError>>, MyClass) -> ObjCBool
13+
// CHECK: [[NEXT_STACK:%.*]] = alloc_stack $@sil_unmanaged Optional<NSError>
14+
// CHECK: [[VAL:%.*]] = load [[STACK]] : $*Optional<NSError>
15+
// CHECK: [[UNMANAGED:%.*]] = ref_to_unmanaged [[VAL]]
16+
// CHECK: store [[UNMANAGED]] to [[NEXT_STACK]]
17+
// CHECK: [[PTR:%.*]] = address_to_pointer [[NEXT_STACK]]
18+
// CHECK: [[AUMP:%.*]] = struct $AutoreleasingUnsafeMutablePointer<NSError> ([[PTR]] :
19+
// CHECK: [[OPT_AUMP:%.*]] = enum $Optional<AutoreleasingUnsafeMutablePointer<NSError>>, #Optional.some!enumelt, [[AUMP]] : $AutoreleasingUnsafeMutablePointer<NSError>
20+
// CHECK: apply {{%.*}}([[OPT_AUMP]],
21+
// CHECK: } // end sil function '$s4main1fyyF'
22+
23+
func f() {
24+
let c = MyClass()
25+
do {
26+
try c.submit()
27+
} catch {}
28+
}
29+
30+
f()

0 commit comments

Comments
 (0)