Skip to content

Commit 0d1095e

Browse files
authored
Merge pull request #66262 from beccadax/your-implementation-is-required
Support required inits in @objcImpl
2 parents 58ff42a + b14c00d commit 0d1095e

File tree

6 files changed

+70
-2
lines changed

6 files changed

+70
-2
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,11 @@ ERROR(objc_implementation_type_mismatch,none,
17091709
"header",
17101710
(DescriptiveDeclKind, ValueDecl *, Type, Type))
17111711

1712+
ERROR(objc_implementation_required_attr_mismatch,none,
1713+
"%0 %1 %select{should not|should}2 be 'required' to match %0 declared by "
1714+
"the header",
1715+
(DescriptiveDeclKind, ValueDecl *, bool))
1716+
17121717
ERROR(objc_implementation_wrong_objc_name,none,
17131718
"selector %0 for %1 %2 not found in header; did you mean %3?",
17141719
(ObjCSelector, DescriptiveDeclKind, ValueDecl *, ObjCSelector))

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2699,7 +2699,7 @@ void AttributeChecker::visitRequiredAttr(RequiredAttr *attr) {
26992699
// The constructor must be declared within the class itself.
27002700
// FIXME: Allow an SDK overlay to add a required initializer to a class
27012701
// defined in Objective-C
2702-
if (!isa<ClassDecl>(ctor->getDeclContext()) &&
2702+
if (!isa<ClassDecl>(ctor->getDeclContext()->getImplementedObjCContext()) &&
27032703
!isObjCClassExtensionInOverlay(ctor->getDeclContext())) {
27042704
diagnose(ctor, diag::required_initializer_in_extension, parentTy)
27052705
.highlight(attr->getLocation());

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3023,6 +3023,7 @@ class ObjCImplementationChecker {
30233023
WrongDeclKind,
30243024
WrongType,
30253025
WrongWritability,
3026+
WrongRequiredAttr,
30263027

30273028
Match,
30283029
MatchWithExplicitObjCName,
@@ -3320,6 +3321,10 @@ class ObjCImplementationChecker {
33203321
!cast<AbstractStorageDecl>(cand)->isSettable(nullptr))
33213322
return MatchOutcome::WrongWritability;
33223323

3324+
if (auto reqCtor = dyn_cast<ConstructorDecl>(req))
3325+
if (reqCtor->isRequired() != cast<ConstructorDecl>(cand)->isRequired())
3326+
return MatchOutcome::WrongRequiredAttr;
3327+
33233328
// If we got here, everything matched. But at what quality?
33243329
if (explicitObjCName)
33253330
return MatchOutcome::MatchWithExplicitObjCName;
@@ -3407,6 +3412,22 @@ class ObjCImplementationChecker {
34073412
diagnose(cand, diag::objc_implementation_must_be_settable,
34083413
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
34093414
return;
3415+
3416+
case MatchOutcome::WrongRequiredAttr: {
3417+
bool shouldBeRequired = cast<ConstructorDecl>(req)->isRequired();
3418+
3419+
auto diag =
3420+
diagnose(cand, diag::objc_implementation_required_attr_mismatch,
3421+
cand->getDescriptiveKind(), cand, shouldBeRequired);
3422+
3423+
if (shouldBeRequired)
3424+
diag.fixItInsert(cand->getAttributeInsertionLoc(/*forModifier=*/true),
3425+
"required ");
3426+
else
3427+
diag.fixItRemove(cand->getAttrs().getAttribute<RequiredAttr>()
3428+
->getLocation());
3429+
return;
3430+
}
34103431
}
34113432

34123433
llvm_unreachable("Unknown MatchOutcome");

test/decl/ext/Inputs/objc_implementation.h

Lines changed: 10 additions & 1 deletion
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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,21 @@
145145
// OK
146146
}
147147

148+
@objc(initFromProtocol1:)
149+
required public init?(fromProtocol1: CInt) {
150+
// OK
151+
}
152+
153+
@objc(initFromProtocol2:)
154+
public init?(fromProtocol2: CInt) {
155+
// expected-error@-1 {{initializer 'init(fromProtocol2:)' should be 'required' to match initializer declared by the header}} {{3-3=required }}
156+
}
157+
158+
@objc(initNotFromProtocol:)
159+
required public init?(notFromProtocol: CInt) {
160+
// expected-error@-1 {{initializer 'init(notFromProtocol:)' should not be 'required' to match initializer declared by the header}} {{3-12=}}
161+
}
162+
148163
class func classMethod1(_: CInt) {
149164
// OK
150165
}

test/decl/ext/objc_implementation_conflicts.swift

Lines changed: 18 additions & 0 deletions
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)