Skip to content

Commit 67cb677

Browse files
authored
Merge pull request #67063 from beccadax/unconventional-implementation-5.9
2 parents 54f1375 + 9e391d8 commit 67cb677

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,6 +1657,49 @@ ERROR(objc_implementation_required_attr_mismatch,none,
16571657
"the header",
16581658
(DescriptiveDeclKind, ValueDecl *, bool))
16591659

1660+
ERROR(objc_implementation_candidate_has_error_convention,none,
1661+
"%0 %1 does not match the declaration in the header because it throws an "
1662+
"error",
1663+
(DescriptiveDeclKind, ValueDecl *))
1664+
1665+
ERROR(objc_implementation_candidate_lacks_error_convention,none,
1666+
"%0 %1 does not match the declaration in the header because it does not "
1667+
"throw an error",
1668+
(DescriptiveDeclKind, ValueDecl *))
1669+
1670+
#define SELECT_FOREIGN_ERROR_CONVENTION_KIND \
1671+
"select{returning zero|returning non-zero|returning zero or a result|" \
1672+
"returning nil|setting the error parameter|%error}"
1673+
1674+
ERROR(objc_implementation_mismatched_error_convention_kind,none,
1675+
"%0 %1 does not match the declaration in the header because it indicates "
1676+
"an error by %" SELECT_FOREIGN_ERROR_CONVENTION_KIND "2, rather than by "
1677+
"%" SELECT_FOREIGN_ERROR_CONVENTION_KIND "3",
1678+
(DescriptiveDeclKind, ValueDecl *, unsigned, unsigned))
1679+
1680+
ERROR(objc_implementation_mismatched_error_convention_index,none,
1681+
"%0 %1 does not match the declaration in the header because it uses "
1682+
"parameter #%2 for the error, not parameter #%3; a selector part called "
1683+
"'error:' can control which parameter to use",
1684+
(DescriptiveDeclKind, ValueDecl *, unsigned, unsigned))
1685+
1686+
ERROR(objc_implementation_mismatched_error_convention_void_param,none,
1687+
"%0 %1 does not match the declaration in the header because it "
1688+
"%select{removes the error parameter|makes the error parameter 'Void'}2 "
1689+
"rather than %select{making it 'Void'|removing it}2",
1690+
(DescriptiveDeclKind, ValueDecl *, bool))
1691+
1692+
ERROR(objc_implementation_mismatched_error_convention_ownership,none,
1693+
"%0 %1 does not match the declaration in the header because it "
1694+
"%select{does not own|owns}2 the error parameter",
1695+
(DescriptiveDeclKind, ValueDecl *, bool))
1696+
1697+
ERROR(objc_implementation_mismatched_error_convention_other,none,
1698+
"%0 %1 does not match the declaration in the header because it uses a "
1699+
"different Objective-C error convention; please file a bug report with a "
1700+
"sample project, as the compiler should be able to describe the mismatch",
1701+
(DescriptiveDeclKind, ValueDecl *))
1702+
16601703
ERROR(objc_implementation_wrong_objc_name,none,
16611704
"selector %0 for %1 %2 not found in header; did you mean %3?",
16621705
(ObjCSelector, DescriptiveDeclKind, ValueDecl *, ObjCSelector))

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3043,6 +3043,7 @@ class ObjCImplementationChecker {
30433043
WrongType,
30443044
WrongWritability,
30453045
WrongRequiredAttr,
3046+
WrongForeignErrorConvention,
30463047

30473048
Match,
30483049
MatchWithExplicitObjCName,
@@ -3344,6 +3345,11 @@ class ObjCImplementationChecker {
33443345
if (reqCtor->isRequired() != cast<ConstructorDecl>(cand)->isRequired())
33453346
return MatchOutcome::WrongRequiredAttr;
33463347

3348+
if (auto reqAFD = dyn_cast<AbstractFunctionDecl>(req))
3349+
if (reqAFD->getForeignErrorConvention() !=
3350+
cast<AbstractFunctionDecl>(cand)->getForeignErrorConvention())
3351+
return MatchOutcome::WrongForeignErrorConvention;
3352+
33473353
// If we got here, everything matched. But at what quality?
33483354
if (explicitObjCName)
33493355
return MatchOutcome::MatchWithExplicitObjCName;
@@ -3447,6 +3453,49 @@ class ObjCImplementationChecker {
34473453
->getLocation());
34483454
return;
34493455
}
3456+
3457+
case MatchOutcome::WrongForeignErrorConvention: {
3458+
auto reqConv = cast<AbstractFunctionDecl>(req)->getForeignErrorConvention();
3459+
auto candConv = cast<AbstractFunctionDecl>(cand)->getForeignErrorConvention();
3460+
3461+
if (reqConv && !candConv)
3462+
diagnose(cand,
3463+
diag::objc_implementation_candidate_has_error_convention,
3464+
cand->getDescriptiveKind(), cand);
3465+
else if (!reqConv && candConv)
3466+
diagnose(cand,
3467+
diag::objc_implementation_candidate_lacks_error_convention,
3468+
cand->getDescriptiveKind(), cand);
3469+
else if (reqConv->getKind() != candConv->getKind())
3470+
diagnose(cand,
3471+
diag::objc_implementation_mismatched_error_convention_kind,
3472+
cand->getDescriptiveKind(), cand, candConv->getKind(),
3473+
reqConv->getKind());
3474+
else if (reqConv->getErrorParameterIndex()
3475+
!= candConv->getErrorParameterIndex())
3476+
diagnose(cand,
3477+
diag::objc_implementation_mismatched_error_convention_index,
3478+
cand->getDescriptiveKind(), cand,
3479+
candConv->getErrorParameterIndex() + 1,
3480+
reqConv->getErrorParameterIndex() + 1);
3481+
else if (reqConv->isErrorParameterReplacedWithVoid()
3482+
!= candConv->isErrorParameterReplacedWithVoid())
3483+
diagnose(cand,
3484+
diag::objc_implementation_mismatched_error_convention_void_param,
3485+
cand->getDescriptiveKind(), cand,
3486+
candConv->isErrorParameterReplacedWithVoid());
3487+
else if (reqConv->isErrorOwned() != candConv->isErrorOwned())
3488+
diagnose(cand,
3489+
diag::objc_implementation_mismatched_error_convention_ownership,
3490+
cand->getDescriptiveKind(), cand, candConv->isErrorOwned());
3491+
else
3492+
// Catch-all; probably shouldn't happen.
3493+
diagnose(cand,
3494+
diag::objc_implementation_mismatched_error_convention_other,
3495+
cand->getDescriptiveKind(), cand);
3496+
3497+
return;
3498+
}
34503499
}
34513500

34523501
llvm_unreachable("Unknown MatchOutcome");

test/decl/ext/Inputs/objc_implementation.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@
106106

107107
- (void)doSomethingOverloadedWithCompletionHandler:(void (^ _Nonnull)())completionHandler;
108108
- (void)doSomethingOverloaded __attribute__((__swift_attr__("@_unavailableFromAsync(message: \"Use async doSomethingOverloaded instead.\")")));
109+
110+
- (BOOL)doSomethingThatCanFailWithHandler:(void (^ _Nonnull)())handler error:(NSError **)error;
111+
- (BOOL)doSomethingElseThatCanFail:(NSError **)error handler:(void (^ _Nonnull)())handler;
112+
- (BOOL)doSomethingThatCanFailWithWeirdParameterWithHandler:(void (^ _Nonnull)())handler :(NSError **)error;
113+
- (int)doSomethingThatCanFailWithWeirdReturnCodeWithError:(NSError **)error __attribute__((swift_error(nonzero_result)));
114+
109115
@end
110116

111117
@protocol PartiallyOptionalProtocol

test/decl/ext/objc_implementation.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,26 @@ protocol EmptySwiftProto {}
335335
@available(*, noasync)
336336
@objc(doSomethingOverloaded)
337337
public func doSomethingOverloaded() {}
338+
339+
@objc(doSomethingThatCanFailWithHandler:error:)
340+
public func doSomethingThatCanFail(handler: @escaping () -> Void) throws {
341+
// OK
342+
}
343+
344+
@objc(doSomethingElseThatCanFail:handler:)
345+
public func doSomethingElseThatCanFail(handler: @escaping () -> Void) throws {
346+
// OK
347+
}
348+
349+
@objc(doSomethingThatCanFailWithWeirdParameterWithHandler::)
350+
public func doSomethingThatCanFailWithWeirdParameter(handler: @escaping () -> Void) throws {
351+
// expected-warning@-1 {{instance method 'doSomethingThatCanFailWithWeirdParameter(handler:)' does not match the declaration in the header because it uses parameter #1 for the error, not parameter #2; a selector part called 'error:' can control which parameter to use}}
352+
}
353+
354+
@objc(doSomethingThatCanFailWithWeirdReturnCodeWithError:)
355+
public func doSomethingThatCanFailWithWeirdReturnCode() throws {
356+
// expected-warning@-1 {{instance method 'doSomethingThatCanFailWithWeirdReturnCode()' does not match the declaration in the header because it indicates an error by returning zero, rather than by returning non-zero}}
357+
}
338358
}
339359

340360
@_objcImplementation(Conformance) extension ObjCClass {

0 commit comments

Comments
 (0)