Skip to content

Commit 75a04b0

Browse files
authored
Merge pull request #66862 from beccadax/your-implementation-is-required-5.9
2 parents 1959858 + d7271f9 commit 75a04b0

File tree

6 files changed

+70
-2
lines changed

6 files changed

+70
-2
lines changed

include/swift/AST/DiagnosticsSema.def

+5
Original file line numberDiff line numberDiff line change
@@ -1652,6 +1652,11 @@ ERROR(objc_implementation_type_mismatch,none,
16521652
"header",
16531653
(DescriptiveDeclKind, ValueDecl *, Type, Type))
16541654

1655+
ERROR(objc_implementation_required_attr_mismatch,none,
1656+
"%0 %1 %select{should not|should}2 be 'required' to match %0 declared by "
1657+
"the header",
1658+
(DescriptiveDeclKind, ValueDecl *, bool))
1659+
16551660
ERROR(objc_implementation_wrong_objc_name,none,
16561661
"selector %0 for %1 %2 not found in header; did you mean %3?",
16571662
(ObjCSelector, DescriptiveDeclKind, ValueDecl *, ObjCSelector))

lib/Sema/TypeCheckAttr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2661,7 +2661,7 @@ void AttributeChecker::visitRequiredAttr(RequiredAttr *attr) {
26612661
// The constructor must be declared within the class itself.
26622662
// FIXME: Allow an SDK overlay to add a required initializer to a class
26632663
// defined in Objective-C
2664-
if (!isa<ClassDecl>(ctor->getDeclContext()) &&
2664+
if (!isa<ClassDecl>(ctor->getDeclContext()->getImplementedObjCContext()) &&
26652665
!isObjCClassExtensionInOverlay(ctor->getDeclContext())) {
26662666
diagnose(ctor, diag::required_initializer_in_extension, parentTy)
26672667
.highlight(attr->getLocation());

lib/Sema/TypeCheckDeclObjC.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -3042,6 +3042,7 @@ class ObjCImplementationChecker {
30423042
WrongDeclKind,
30433043
WrongType,
30443044
WrongWritability,
3045+
WrongRequiredAttr,
30453046

30463047
Match,
30473048
MatchWithExplicitObjCName,
@@ -3339,6 +3340,10 @@ class ObjCImplementationChecker {
33393340
!cast<AbstractStorageDecl>(cand)->isSettable(nullptr))
33403341
return MatchOutcome::WrongWritability;
33413342

3343+
if (auto reqCtor = dyn_cast<ConstructorDecl>(req))
3344+
if (reqCtor->isRequired() != cast<ConstructorDecl>(cand)->isRequired())
3345+
return MatchOutcome::WrongRequiredAttr;
3346+
33423347
// If we got here, everything matched. But at what quality?
33433348
if (explicitObjCName)
33443349
return MatchOutcome::MatchWithExplicitObjCName;
@@ -3426,6 +3431,22 @@ class ObjCImplementationChecker {
34263431
diagnose(cand, diag::objc_implementation_must_be_settable,
34273432
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
34283433
return;
3434+
3435+
case MatchOutcome::WrongRequiredAttr: {
3436+
bool shouldBeRequired = cast<ConstructorDecl>(req)->isRequired();
3437+
3438+
auto diag =
3439+
diagnose(cand, diag::objc_implementation_required_attr_mismatch,
3440+
cand->getDescriptiveKind(), cand, shouldBeRequired);
3441+
3442+
if (shouldBeRequired)
3443+
diag.fixItInsert(cand->getAttributeInsertionLoc(/*forModifier=*/true),
3444+
"required ");
3445+
else
3446+
diag.fixItRemove(cand->getAttrs().getAttribute<RequiredAttr>()
3447+
->getLocation());
3448+
return;
3449+
}
34293450
}
34303451

34313452
llvm_unreachable("Unknown MatchOutcome");

test/decl/ext/Inputs/objc_implementation.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,16 @@
1212

1313
@end
1414

15-
@interface ObjCClass : ObjCBaseClass
15+
@protocol ObjCProto
16+
17+
- (instancetype)initFromProtocol1:(int)param;
18+
- (instancetype)initFromProtocol2:(int)param;
19+
20+
@end
21+
22+
@interface ObjCClass : ObjCBaseClass <ObjCProto>
23+
24+
- (instancetype)initNotFromProtocol:(int)param;
1625

1726
- (void)methodFromHeader1:(int)param;
1827
- (void)methodFromHeader2:(int)param;

test/decl/ext/objc_implementation.swift

+15
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,21 @@ protocol EmptySwiftProto {}
149149
// OK
150150
}
151151

152+
@objc(initFromProtocol1:)
153+
required public init?(fromProtocol1: CInt) {
154+
// OK
155+
}
156+
157+
@objc(initFromProtocol2:)
158+
public init?(fromProtocol2: CInt) {
159+
// expected-warning@-1 {{initializer 'init(fromProtocol2:)' should be 'required' to match initializer declared by the header}} {{3-3=required }}
160+
}
161+
162+
@objc(initNotFromProtocol:)
163+
required public init?(notFromProtocol: CInt) {
164+
// expected-warning@-1 {{initializer 'init(notFromProtocol:)' should not be 'required' to match initializer declared by the header}} {{3-12=}}
165+
}
166+
152167
class func classMethod1(_: CInt) {
153168
// OK
154169
}

test/decl/ext/objc_implementation_conflicts.swift

+18
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,24 @@ import objc_implementation_private
146146
super.init(fromSuperclass2: v)
147147
}
148148

149+
@objc(initFromProtocol1:)
150+
required public init?(fromProtocol1 v: CInt) {
151+
// OK
152+
super.init(fromSuperclass: v)
153+
}
154+
155+
@objc(initFromProtocol2:)
156+
required public init?(fromProtocol2 v: CInt) {
157+
// OK
158+
super.init(fromSuperclass: v)
159+
}
160+
161+
@objc(initNotFromProtocol:)
162+
public init?(notFromProtocol v: CInt) {
163+
// OK
164+
super.init(fromSuperclass: v)
165+
}
166+
149167
class func classMethod1(_: CInt) {}
150168
class func classMethod2(_: CInt) {}
151169
class func classMethod3(_: CInt) {}

0 commit comments

Comments
 (0)