Skip to content

Commit 5c1ce9a

Browse files
authored
Merge pull request #66073 from beccadax/implementation-errors
Diagnose additional @objcImpl member mismatch errors
2 parents 670f5d2 + 9f0928e commit 5c1ce9a

File tree

6 files changed

+248
-74
lines changed

6 files changed

+248
-74
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,20 @@ ERROR(objc_implementation_wrong_category,none,
16451645
"%select{main class interface|category %3}3",
16461646
(DescriptiveDeclKind, ValueDecl *, Identifier, Identifier))
16471647

1648+
ERROR(objc_implementation_wrong_decl_kind,none,
1649+
"%0 %1 does not match the %2 declared by the header",
1650+
(DescriptiveDeclKind, ValueDecl *, DescriptiveDeclKind))
1651+
1652+
ERROR(objc_implementation_must_be_settable,none,
1653+
"%0 %1 should be settable to match the settable %2 declared by the "
1654+
"header",
1655+
(DescriptiveDeclKind, ValueDecl *, DescriptiveDeclKind))
1656+
1657+
ERROR(objc_implementation_type_mismatch,none,
1658+
"%0 %1 of type %2 does not match type %3 declared by the "
1659+
"header",
1660+
(DescriptiveDeclKind, ValueDecl *, Type, Type))
1661+
16481662
ERROR(objc_implementation_wrong_objc_name,none,
16491663
"selector %0 for %1 %2 not found in header; did you mean %3?",
16501664
(ObjCSelector, DescriptiveDeclKind, ValueDecl *, ObjCSelector))

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 146 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2885,15 +2885,6 @@ class ObjCImplementationChecker {
28852885
/// Candidates with their explicit ObjC names, if any.
28862886
llvm::SmallDenseMap<ValueDecl *, ObjCSelector, 16> unmatchedCandidates;
28872887

2888-
/// Key that can be used to uniquely identify a particular Objective-C
2889-
/// method.
2890-
using ObjCMethodKey = std::pair<ObjCSelector, char>;
2891-
2892-
/// Mapping from Objective-C methods to the set of requirements within this
2893-
/// protocol that have the same selector and instance/class designation.
2894-
llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4>
2895-
objcMethodRequirements;
2896-
28972888
public:
28982889
ObjCImplementationChecker(ExtensionDecl *ext)
28992890
: diags(ext->getASTContext().Diags)
@@ -2915,8 +2906,30 @@ class ObjCImplementationChecker {
29152906
}
29162907

29172908
private:
2918-
auto getObjCMethodKey(AbstractFunctionDecl *func) const -> ObjCMethodKey {
2919-
return ObjCMethodKey(func->getObjCSelector(), func->isInstanceMember());
2909+
static bool hasAsync(ValueDecl *member) {
2910+
if (!member)
2911+
return false;
2912+
2913+
if (auto func = dyn_cast<AbstractFunctionDecl>(member))
2914+
return func->hasAsync();
2915+
2916+
if (auto storage = dyn_cast<AbstractStorageDecl>(member))
2917+
return hasAsync(storage->getEffectfulGetAccessor());
2918+
2919+
return false;
2920+
}
2921+
2922+
static ValueDecl *getAsyncAlternative(ValueDecl *req) {
2923+
if (auto func = dyn_cast<AbstractFunctionDecl>(req)) {
2924+
auto asyncFunc = func->getAsyncAlternative();
2925+
2926+
if (auto asyncAccessor = dyn_cast<AccessorDecl>(asyncFunc))
2927+
return asyncAccessor->getStorage();
2928+
2929+
return asyncFunc;
2930+
}
2931+
2932+
return nullptr;
29202933
}
29212934

29222935
void addRequirements(IterableDeclContext *idc) {
@@ -2932,12 +2945,13 @@ class ObjCImplementationChecker {
29322945
if (member->getAttrs().isUnavailable(member->getASTContext()))
29332946
continue;
29342947

2948+
// Skip async versions of members. We'll match against the completion
2949+
// handler versions, hopping over to `getAsyncAlternative()` if needed.
2950+
if (hasAsync(member))
2951+
continue;
2952+
29352953
auto inserted = unmatchedRequirements.insert(member);
29362954
assert(inserted && "objc interface member added twice?");
2937-
2938-
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2939-
objcMethodRequirements[getObjCMethodKey(func)].push_back(func);
2940-
}
29412955
}
29422956
}
29432957

@@ -2998,6 +3012,9 @@ class ObjCImplementationChecker {
29983012
WrongImplicitObjCName,
29993013
WrongStaticness,
30003014
WrongCategory,
3015+
WrongDeclKind,
3016+
WrongType,
3017+
WrongWritability,
30013018

30023019
Match,
30033020
MatchWithExplicitObjCName,
@@ -3031,19 +3048,6 @@ class ObjCImplementationChecker {
30313048
}
30323049
};
30333050

3034-
/// Determine whether the set of matched requirements are ambiguous for the
3035-
/// given candidate.
3036-
bool areRequirementsAmbiguous(const BestMatchList &reqs, ValueDecl *cand) {
3037-
if (reqs.matches.size() != 2)
3038-
return reqs.matches.size() > 2;
3039-
3040-
bool firstIsAsyncAlternative =
3041-
matchesAsyncAlternative(reqs.matches[0], cand);
3042-
bool secondIsAsyncAlternative =
3043-
matchesAsyncAlternative(reqs.matches[1], cand);
3044-
return firstIsAsyncAlternative == secondIsAsyncAlternative;
3045-
}
3046-
30473051
void matchRequirementsAtThreshold(MatchOutcome threshold) {
30483052
SmallString<32> scratch;
30493053

@@ -3103,14 +3107,11 @@ class ObjCImplementationChecker {
31033107
// removing them.
31043108
requirementsToRemove.set_union(matchedRequirements.matches);
31053109

3106-
if (!areRequirementsAmbiguous(matchedRequirements, cand)) {
3110+
if (matchedRequirements.matches.size() == 1) {
31073111
// Note that this is BestMatchList::insert(), so it'll only keep the
31083112
// matches with the best outcomes.
3109-
for (auto req : matchedRequirements.matches) {
3110-
matchesByRequirement[req]
3111-
.insert(cand, matchedRequirements.currentOutcome);
3112-
}
3113-
3113+
matchesByRequirement[matchedRequirements.matches.front()]
3114+
.insert(cand, matchedRequirements.currentOutcome);
31143115
continue;
31153116
}
31163117

@@ -3192,40 +3193,89 @@ class ObjCImplementationChecker {
31923193
unmatchedCandidates.erase(cand);
31933194
}
31943195

3195-
/// Whether the candidate matches the async alternative of the given
3196-
/// requirement.
3197-
bool matchesAsyncAlternative(ValueDecl *req, ValueDecl *cand) const {
3198-
auto reqFunc = dyn_cast<AbstractFunctionDecl>(req);
3199-
if (!reqFunc)
3200-
return false;
3196+
static bool areSwiftNamesEqual(DeclName lhs, DeclName rhs) {
3197+
// Conflate `foo()` and `foo`. This allows us to diagnose
3198+
// method-vs.-property mistakes more nicely.
32013199

3202-
auto candFunc = dyn_cast<AbstractFunctionDecl>(cand);
3203-
if (!candFunc)
3204-
return false;
3200+
if (lhs.isCompoundName() && lhs.getArgumentNames().empty())
3201+
lhs = lhs.getBaseName();
32053202

3206-
if (reqFunc->hasAsync() == candFunc->hasAsync())
3207-
return false;
3203+
if (rhs.isCompoundName() && rhs.getArgumentNames().empty())
3204+
rhs = rhs.getBaseName();
32083205

3209-
auto otherReqFuncs =
3210-
objcMethodRequirements.find(getObjCMethodKey(reqFunc));
3211-
if (otherReqFuncs == objcMethodRequirements.end())
3212-
return false;
3206+
return lhs == rhs;
3207+
}
32133208

3214-
for (auto otherReqFunc : otherReqFuncs->second) {
3215-
if (otherReqFunc->getName() == cand->getName() &&
3216-
otherReqFunc->hasAsync() == candFunc->hasAsync() &&
3217-
req->getObjCRuntimeName() == cand->getObjCRuntimeName())
3218-
return true;
3219-
}
3209+
static bool matchParamTypes(Type reqTy, Type implTy, ValueDecl *implDecl) {
3210+
TypeMatchOptions matchOpts = {};
3211+
3212+
// Try a plain type match.
3213+
if (implTy->matchesParameter(reqTy, matchOpts))
3214+
return true;
3215+
3216+
// If the implementation type is IUO, try unwrapping it.
3217+
if (auto unwrappedImplTy = implTy->getOptionalObjectType())
3218+
return implDecl->isImplicitlyUnwrappedOptional()
3219+
&& unwrappedImplTy->matchesParameter(reqTy, matchOpts);
32203220

32213221
return false;
32223222
}
32233223

3224-
MatchOutcome matches(ValueDecl *req, ValueDecl *cand,
3225-
ObjCSelector explicitObjCName) const {
3224+
static bool matchTypes(Type reqTy, Type implTy, ValueDecl *implDecl) {
3225+
TypeMatchOptions matchOpts = {};
3226+
3227+
// Try a plain type match.
3228+
if (reqTy->matches(implTy, matchOpts))
3229+
return true;
3230+
3231+
// If the implementation type is optional, try unwrapping it.
3232+
if (auto unwrappedImplTy = implTy->getOptionalObjectType())
3233+
return implDecl->isImplicitlyUnwrappedOptional()
3234+
&& reqTy->matches(unwrappedImplTy, matchOpts);
3235+
3236+
// Apply these rules to the result type and parameters if it's a function
3237+
// type.
3238+
if (auto funcReqTy = reqTy->getAs<AnyFunctionType>())
3239+
if (auto funcImplTy = implTy->getAs<AnyFunctionType>())
3240+
return funcReqTy->matchesFunctionType(funcImplTy, matchOpts,
3241+
[=]() -> bool {
3242+
auto reqParams = funcReqTy->getParams();
3243+
auto implParams = funcImplTy->getParams();
3244+
if (reqParams.size() != implParams.size())
3245+
return false;
3246+
3247+
auto implParamList =
3248+
cast<AbstractFunctionDecl>(implDecl)->getParameters();
3249+
3250+
for (auto i : indices(reqParams)) {
3251+
const auto &reqParam = reqParams[i];
3252+
const auto &implParam = implParams[i];
3253+
ParamDecl *implParamDecl = implParamList->get(i);
3254+
3255+
if (!matchParamTypes(reqParam.getOldType(), implParam.getOldType(),
3256+
implParamDecl))
3257+
return false;
3258+
}
3259+
3260+
return matchTypes(funcReqTy->getResult(), funcImplTy->getResult(),
3261+
implDecl);
3262+
});
3263+
3264+
return false;
3265+
}
3266+
3267+
static Type getMemberType(ValueDecl *decl) {
3268+
if (isa<AbstractFunctionDecl>(decl))
3269+
// Strip off the uncurried `self` parameter.
3270+
return decl->getInterfaceType()->getAs<AnyFunctionType>()->getResult();
3271+
return decl->getInterfaceType();
3272+
}
3273+
3274+
MatchOutcome matchesImpl(ValueDecl *req, ValueDecl *cand,
3275+
ObjCSelector explicitObjCName) const {
32263276
bool hasObjCNameMatch =
32273277
req->getObjCRuntimeName() == cand->getObjCRuntimeName();
3228-
bool hasSwiftNameMatch = req->getName() == cand->getName();
3278+
bool hasSwiftNameMatch = areSwiftNamesEqual(req->getName(), cand->getName());
32293279

32303280
// If neither the ObjC nor Swift names match, there's absolutely no reason
32313281
// to think these two methods are related.
@@ -3238,10 +3288,7 @@ class ObjCImplementationChecker {
32383288
&& req->getObjCRuntimeName() != explicitObjCName)
32393289
return MatchOutcome::WrongExplicitObjCName;
32403290

3241-
// If the ObjC selectors matched but the Swift names do not, and these are
3242-
// functions with mismatched 'async', check whether the "other" requirement
3243-
// (the completion-handler or async version)'s Swift name matches.
3244-
if (!hasSwiftNameMatch && !matchesAsyncAlternative(req, cand))
3291+
if (!hasSwiftNameMatch)
32453292
return MatchOutcome::WrongSwiftName;
32463293

32473294
if (!hasObjCNameMatch)
@@ -3254,9 +3301,16 @@ class ObjCImplementationChecker {
32543301
!= req->getDeclContext())
32553302
return MatchOutcome::WrongCategory;
32563303

3257-
// FIXME: Diagnose candidate without a required setter
3258-
// FIXME: Diagnose declaration kind mismatches
3259-
// FIXME: Diagnose type mismatches (with allowance for extra optionality)
3304+
if (cand->getKind() != req->getKind())
3305+
return MatchOutcome::WrongDeclKind;
3306+
3307+
if (!matchTypes(getMemberType(req), getMemberType(cand), cand))
3308+
return MatchOutcome::WrongType;
3309+
3310+
if (auto reqVar = dyn_cast<AbstractStorageDecl>(req))
3311+
if (reqVar->isSettable(nullptr) &&
3312+
!cast<AbstractStorageDecl>(cand)->isSettable(nullptr))
3313+
return MatchOutcome::WrongWritability;
32603314

32613315
// If we got here, everything matched. But at what quality?
32623316
if (explicitObjCName)
@@ -3265,6 +3319,17 @@ class ObjCImplementationChecker {
32653319
return MatchOutcome::Match;
32663320
}
32673321

3322+
MatchOutcome matches(ValueDecl *req, ValueDecl *cand,
3323+
ObjCSelector explicitObjCName) const {
3324+
// If the candidate we're considering is async, see if the requirement has
3325+
// an async alternate and try to match against that instead.
3326+
if (hasAsync(cand))
3327+
if (auto asyncAltReq = getAsyncAlternative(req))
3328+
return matchesImpl(asyncAltReq, cand, explicitObjCName);
3329+
3330+
return matchesImpl(req, cand, explicitObjCName);
3331+
}
3332+
32683333
void diagnoseOutcome(MatchOutcome outcome, ValueDecl *req, ValueDecl *cand,
32693334
ObjCSelector explicitObjCName) {
32703335
auto reqObjCName = *req->getObjCRuntimeName();
@@ -3318,6 +3383,22 @@ class ObjCImplementationChecker {
33183383
getCategoryName(cand->getDeclContext()->
33193384
getImplementedObjCContext()));
33203385
return;
3386+
3387+
case MatchOutcome::WrongDeclKind:
3388+
diagnose(cand, diag::objc_implementation_wrong_decl_kind,
3389+
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
3390+
return;
3391+
3392+
case MatchOutcome::WrongType:
3393+
diagnose(cand, diag::objc_implementation_type_mismatch,
3394+
cand->getDescriptiveKind(), cand,
3395+
getMemberType(cand), getMemberType(req));
3396+
return;
3397+
3398+
case MatchOutcome::WrongWritability:
3399+
diagnose(cand, diag::objc_implementation_must_be_settable,
3400+
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
3401+
return;
33213402
}
33223403

33233404
llvm_unreachable("Unknown MatchOutcome");

test/IRGen/objc_implementation.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// CHECK: [[selector_data_implProperty:@[^, ]+]] = private global [13 x i8] c"implProperty\00", section "__TEXT,__objc_methname,cstring_literals", align 1
2323
// CHECK: [[selector_data_setImplProperty_:@[^, ]+]] = private global [17 x i8] c"setImplProperty:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
2424
// CHECK: [[selector_data__cxx_destruct:@[^, ]+]] = private global [14 x i8] c".cxx_destruct\00", section "__TEXT,__objc_methname,cstring_literals", align 1
25-
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [7 x { i8*, i8*, i8* }] } { i32 24, i32 7, [7 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[selector_data_implProperty]], i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.i16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[selector_data_setImplProperty_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v20@0:8i16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[selector_data_mainMethod_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v20@0:8i16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(copyWithZone:)", i64 0, i64 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @".str.11.@24@0:8^v16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE4copy4withyp10ObjectiveC6NSZoneV_tFTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_selector_data(dealloc)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.v16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[selector_data__cxx_destruct]], i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.v16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" to i8*) }] }, section "__DATA, __objc_data", align 8
25+
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [7 x { i8*, i8*, i8* }] } { i32 24, i32 7, [7 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationEABycfcTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[selector_data_implProperty]], i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.i16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvgTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[selector_data_setImplProperty_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v20@0:8i16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvsTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[selector_data_mainMethod_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v20@0:8i16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(copyWithZone:)", i64 0, i64 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @".str.11.@24@0:8^v16", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_selector_data(dealloc)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.v16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassC19objc_implementationEfDTo{{(\.ptrauth)?}}" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[selector_data__cxx_destruct]], i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.v16@0:8", i64 0, i64 0), i8* bitcast ({{.*}}* @"$sSo9ImplClassCfETo{{(\.ptrauth)?}}" to i8*) }] }, section "__DATA, __objc_data", align 8
2626
// CHECK: [[_IVARS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [2 x { i64*, i8*, i8*, i32, i32 }] } { i32 32, i32 2, [2 x { i64*, i8*, i8*, i32, i32 }] [{ i64*, i8*, i8*, i32, i32 } { i64* @"$sSo9ImplClassC19objc_implementationE12implPropertys5Int32VvpWvd", i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.12.implProperty, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 2, i32 4 }, { i64*, i8*, i8*, i32, i32 } { i64* @"$sSo9ImplClassC19objc_implementationE13implProperty2So8NSObjectCSgvpWvd", i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.13.implProperty2, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
2727
// CHECK: [[_PROPERTIES_ImplClass:@[^, ]+]] = internal constant { i32, i32, [1 x { i8*, i8* }] } { i32 16, i32 1, [1 x { i8*, i8* }] [{ i8*, i8* } { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.12.implProperty, i64 0, i64 0), i8* getelementptr inbounds ([19 x i8], [19 x i8]* @".str.18.Ti,N,VimplProperty", i64 0, i64 0) }] }, section "__DATA, __objc_const", align 8
2828
// FIXME: Should just be @_PROTOCOLS_ImplClass, but an IRGen bug causes the protocol list to be emitted twice.
@@ -51,7 +51,7 @@
5151
@objc func mainMethod(_: Int32) { print(implProperty) }
5252

5353
@objc(copyWithZone:)
54-
func copy(with zone: NSZone) -> Any {
54+
func copy(with zone: NSZone?) -> Any? {
5555
let copy = ImplClass()
5656
copy.implProperty = implProperty
5757
copy.implProperty2 = implProperty2
@@ -191,10 +191,10 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
191191
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo"
192192

193193
// Swift calling convention -[ImplClass copyWithZone:]
194-
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE4copy4withyp10ObjectiveC6NSZoneV_tF"
194+
// CHECK-LABEL: define hidden swiftcc void @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tF"
195195

196196
// ObjC calling convention -[ImplClass copyWithZone:]
197-
// CHECK-LABEL: define internal i8* @"$sSo9ImplClassC19objc_implementationE4copy4withyp10ObjectiveC6NSZoneV_tFTo"
197+
// CHECK-LABEL: define internal i8* @"$sSo9ImplClassC19objc_implementationE4copy4withypSg10ObjectiveC6NSZoneVSg_tFTo"
198198

199199
// Swift calling convention -[ImplClass dealloc]
200200
// CHECK-LABEL: define linkonce_odr hidden swiftcc void @"$sSo9ImplClassC19objc_implementationEfD"

0 commit comments

Comments
 (0)