Skip to content

Commit a1397a8

Browse files
committed
[Sema] Don't Emit @objc Fixits Into Extant Modules
Overlays are specifically allowed to do magic things that regular Swift modules are not. In this case, the UIImage and NSImage overlays have extensions that allow them to conform to `_ExpressibleByImageLiteral`. This, unfortunately, means that subclassing these classes with the overlays present is impossible as one must override the required initializers, but one cannot override these initializers since they are declared in an extension. While we cannot correct the overlays without breaking ABI, we can at least make sure we don't attempt to stick @objc into them when users have a go at subclassing these classes. Resolves rdar://59610201
1 parent b5cb81b commit a1397a8

File tree

5 files changed

+48
-1
lines changed

5 files changed

+48
-1
lines changed

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,11 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) {
17721772
bool baseCanBeObjC = canBeRepresentedInObjC(base);
17731773
diags.diagnose(override, diag::override_decl_extension, baseCanBeObjC,
17741774
!isa<ExtensionDecl>(base->getDeclContext()));
1775-
if (baseCanBeObjC) {
1775+
// If the base and the override come from the same module, try to fix
1776+
// the base declaration. Otherwise we can wind up diagnosing into e.g. the
1777+
// SDK overlay modules.
1778+
if (baseCanBeObjC &&
1779+
base->getModuleContext() == override->getModuleContext()) {
17761780
SourceLoc insertionLoc =
17771781
override->getAttributeInsertionLoc(/*forModifier=*/false);
17781782
diags.diagnose(base, diag::overridden_here_can_be_objc)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import Foundation;
2+
3+
@interface Image: NSObject
4+
5+
+ (instancetype)imageNamed:(NSString *)string;
6+
7+
@end

test/ClangImporter/Inputs/custom-modules/module.map

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ module HasSubmodule {
5959
}
6060
}
6161

62+
module ImageInitializers {
63+
header "ImageInitializers.h"
64+
export *
65+
}
66+
6267
module ImportsMissingHeader {
6368
header "ImportsMissingHeader.h"
6469
export *
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@_exported import ImageInitializers
2+
3+
extension Image : _ExpressibleByImageLiteral {
4+
private convenience init!(failableImageLiteral name: String) {
5+
self.init(named: .init(name))
6+
}
7+
8+
@nonobjc
9+
public required convenience init(imageLiteralResourceName name: String) {
10+
self.init(failableImageLiteral: name)
11+
}
12+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-module %S/Inputs/overlay_extension_initializer.swift -Xcc -isystem -Xcc %S/Inputs/custom-modules -module-name ImageInitializers -o %t
3+
// RUN: not %target-swift-frontend -I %S/Inputs/custom-modules -I %t -typecheck -primary-file %s 2>&1 | %FileCheck %s
4+
5+
// REQUIRES: objc_interop
6+
7+
// N.B. This test is a bit odd since we are going to check for the presence of a
8+
// diagnostic being emitted in a different module. The diagnostic verifier isn't
9+
// really setup to test that yet.
10+
11+
import ImageInitializers
12+
13+
final class MyImage : Image {
14+
// CHECK: overriding non-@objc declarations from extensions is not supported
15+
// Make sure we aren't emitting a fixit into the extant module...
16+
// CHECK-NOT: add '@objc' to make this declaration overridable
17+
// CHECK: ImageInitializers.Image:{{.*}}: note: overridden declaration is here
18+
override required convenience init(imageLiteralResourceName name: String) { }
19+
}

0 commit comments

Comments
 (0)