Skip to content

Commit 92a8db2

Browse files
authored
Merge pull request #66149 from beccadax/implementation-errors-5.9
🍒 Diagnose additional @objcImpl member mismatch errors
2 parents abf6585 + 16853f8 commit 92a8db2

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
@@ -1633,6 +1633,20 @@ ERROR(objc_implementation_wrong_category,none,
16331633
"%select{main class interface|category %3}3",
16341634
(DescriptiveDeclKind, ValueDecl *, Identifier, Identifier))
16351635

1636+
ERROR(objc_implementation_wrong_decl_kind,none,
1637+
"%0 %1 does not match the %2 declared by the header",
1638+
(DescriptiveDeclKind, ValueDecl *, DescriptiveDeclKind))
1639+
1640+
ERROR(objc_implementation_must_be_settable,none,
1641+
"%0 %1 should be settable to match the settable %2 declared by the "
1642+
"header",
1643+
(DescriptiveDeclKind, ValueDecl *, DescriptiveDeclKind))
1644+
1645+
ERROR(objc_implementation_type_mismatch,none,
1646+
"%0 %1 of type %2 does not match type %3 declared by the "
1647+
"header",
1648+
(DescriptiveDeclKind, ValueDecl *, Type, Type))
1649+
16361650
ERROR(objc_implementation_wrong_objc_name,none,
16371651
"selector %0 for %1 %2 not found in header; did you mean %3?",
16381652
(ObjCSelector, DescriptiveDeclKind, ValueDecl *, ObjCSelector))

lib/Sema/TypeCheckDeclObjC.cpp

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

2903-
/// Key that can be used to uniquely identify a particular Objective-C
2904-
/// method.
2905-
using ObjCMethodKey = std::pair<ObjCSelector, char>;
2906-
2907-
/// Mapping from Objective-C methods to the set of requirements within this
2908-
/// protocol that have the same selector and instance/class designation.
2909-
llvm::SmallDenseMap<ObjCMethodKey, TinyPtrVector<AbstractFunctionDecl *>, 4>
2910-
objcMethodRequirements;
2911-
29122903
public:
29132904
ObjCImplementationChecker(ExtensionDecl *ext)
29142905
: diags(ext->getASTContext().Diags)
@@ -2930,8 +2921,30 @@ class ObjCImplementationChecker {
29302921
}
29312922

29322923
private:
2933-
auto getObjCMethodKey(AbstractFunctionDecl *func) const -> ObjCMethodKey {
2934-
return ObjCMethodKey(func->getObjCSelector(), func->isInstanceMember());
2924+
static bool hasAsync(ValueDecl *member) {
2925+
if (!member)
2926+
return false;
2927+
2928+
if (auto func = dyn_cast<AbstractFunctionDecl>(member))
2929+
return func->hasAsync();
2930+
2931+
if (auto storage = dyn_cast<AbstractStorageDecl>(member))
2932+
return hasAsync(storage->getEffectfulGetAccessor());
2933+
2934+
return false;
2935+
}
2936+
2937+
static ValueDecl *getAsyncAlternative(ValueDecl *req) {
2938+
if (auto func = dyn_cast<AbstractFunctionDecl>(req)) {
2939+
auto asyncFunc = func->getAsyncAlternative();
2940+
2941+
if (auto asyncAccessor = dyn_cast<AccessorDecl>(asyncFunc))
2942+
return asyncAccessor->getStorage();
2943+
2944+
return asyncFunc;
2945+
}
2946+
2947+
return nullptr;
29352948
}
29362949

29372950
void addRequirements(IterableDeclContext *idc) {
@@ -2947,12 +2960,13 @@ class ObjCImplementationChecker {
29472960
if (member->getAttrs().isUnavailable(member->getASTContext()))
29482961
continue;
29492962

2963+
// Skip async versions of members. We'll match against the completion
2964+
// handler versions, hopping over to `getAsyncAlternative()` if needed.
2965+
if (hasAsync(member))
2966+
continue;
2967+
29502968
auto inserted = unmatchedRequirements.insert(member);
29512969
assert(inserted && "objc interface member added twice?");
2952-
2953-
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
2954-
objcMethodRequirements[getObjCMethodKey(func)].push_back(func);
2955-
}
29562970
}
29572971
}
29582972

@@ -3013,6 +3027,9 @@ class ObjCImplementationChecker {
30133027
WrongImplicitObjCName,
30143028
WrongStaticness,
30153029
WrongCategory,
3030+
WrongDeclKind,
3031+
WrongType,
3032+
WrongWritability,
30163033

30173034
Match,
30183035
MatchWithExplicitObjCName,
@@ -3046,19 +3063,6 @@ class ObjCImplementationChecker {
30463063
}
30473064
};
30483065

3049-
/// Determine whether the set of matched requirements are ambiguous for the
3050-
/// given candidate.
3051-
bool areRequirementsAmbiguous(const BestMatchList &reqs, ValueDecl *cand) {
3052-
if (reqs.matches.size() != 2)
3053-
return reqs.matches.size() > 2;
3054-
3055-
bool firstIsAsyncAlternative =
3056-
matchesAsyncAlternative(reqs.matches[0], cand);
3057-
bool secondIsAsyncAlternative =
3058-
matchesAsyncAlternative(reqs.matches[1], cand);
3059-
return firstIsAsyncAlternative == secondIsAsyncAlternative;
3060-
}
3061-
30623066
void matchRequirementsAtThreshold(MatchOutcome threshold) {
30633067
SmallString<32> scratch;
30643068

@@ -3118,14 +3122,11 @@ class ObjCImplementationChecker {
31183122
// removing them.
31193123
requirementsToRemove.set_union(matchedRequirements.matches);
31203124

3121-
if (!areRequirementsAmbiguous(matchedRequirements, cand)) {
3125+
if (matchedRequirements.matches.size() == 1) {
31223126
// Note that this is BestMatchList::insert(), so it'll only keep the
31233127
// matches with the best outcomes.
3124-
for (auto req : matchedRequirements.matches) {
3125-
matchesByRequirement[req]
3126-
.insert(cand, matchedRequirements.currentOutcome);
3127-
}
3128-
3128+
matchesByRequirement[matchedRequirements.matches.front()]
3129+
.insert(cand, matchedRequirements.currentOutcome);
31293130
continue;
31303131
}
31313132

@@ -3207,40 +3208,89 @@ class ObjCImplementationChecker {
32073208
unmatchedCandidates.erase(cand);
32083209
}
32093210

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

3217-
auto candFunc = dyn_cast<AbstractFunctionDecl>(cand);
3218-
if (!candFunc)
3219-
return false;
3215+
if (lhs.isCompoundName() && lhs.getArgumentNames().empty())
3216+
lhs = lhs.getBaseName();
32203217

3221-
if (reqFunc->hasAsync() == candFunc->hasAsync())
3222-
return false;
3218+
if (rhs.isCompoundName() && rhs.getArgumentNames().empty())
3219+
rhs = rhs.getBaseName();
32233220

3224-
auto otherReqFuncs =
3225-
objcMethodRequirements.find(getObjCMethodKey(reqFunc));
3226-
if (otherReqFuncs == objcMethodRequirements.end())
3227-
return false;
3221+
return lhs == rhs;
3222+
}
32283223

3229-
for (auto otherReqFunc : otherReqFuncs->second) {
3230-
if (otherReqFunc->getName() == cand->getName() &&
3231-
otherReqFunc->hasAsync() == candFunc->hasAsync() &&
3232-
req->getObjCRuntimeName() == cand->getObjCRuntimeName())
3233-
return true;
3234-
}
3224+
static bool matchParamTypes(Type reqTy, Type implTy, ValueDecl *implDecl) {
3225+
TypeMatchOptions matchOpts = {};
3226+
3227+
// Try a plain type match.
3228+
if (implTy->matchesParameter(reqTy, matchOpts))
3229+
return true;
3230+
3231+
// If the implementation type is IUO, try unwrapping it.
3232+
if (auto unwrappedImplTy = implTy->getOptionalObjectType())
3233+
return implDecl->isImplicitlyUnwrappedOptional()
3234+
&& unwrappedImplTy->matchesParameter(reqTy, matchOpts);
32353235

32363236
return false;
32373237
}
32383238

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

32453295
// If neither the ObjC nor Swift names match, there's absolutely no reason
32463296
// to think these two methods are related.
@@ -3253,10 +3303,7 @@ class ObjCImplementationChecker {
32533303
&& req->getObjCRuntimeName() != explicitObjCName)
32543304
return MatchOutcome::WrongExplicitObjCName;
32553305

3256-
// If the ObjC selectors matched but the Swift names do not, and these are
3257-
// functions with mismatched 'async', check whether the "other" requirement
3258-
// (the completion-handler or async version)'s Swift name matches.
3259-
if (!hasSwiftNameMatch && !matchesAsyncAlternative(req, cand))
3306+
if (!hasSwiftNameMatch)
32603307
return MatchOutcome::WrongSwiftName;
32613308

32623309
if (!hasObjCNameMatch)
@@ -3269,9 +3316,16 @@ class ObjCImplementationChecker {
32693316
!= req->getDeclContext())
32703317
return MatchOutcome::WrongCategory;
32713318

3272-
// FIXME: Diagnose candidate without a required setter
3273-
// FIXME: Diagnose declaration kind mismatches
3274-
// FIXME: Diagnose type mismatches (with allowance for extra optionality)
3319+
if (cand->getKind() != req->getKind())
3320+
return MatchOutcome::WrongDeclKind;
3321+
3322+
if (!matchTypes(getMemberType(req), getMemberType(cand), cand))
3323+
return MatchOutcome::WrongType;
3324+
3325+
if (auto reqVar = dyn_cast<AbstractStorageDecl>(req))
3326+
if (reqVar->isSettable(nullptr) &&
3327+
!cast<AbstractStorageDecl>(cand)->isSettable(nullptr))
3328+
return MatchOutcome::WrongWritability;
32753329

32763330
// If we got here, everything matched. But at what quality?
32773331
if (explicitObjCName)
@@ -3280,6 +3334,17 @@ class ObjCImplementationChecker {
32803334
return MatchOutcome::Match;
32813335
}
32823336

3337+
MatchOutcome matches(ValueDecl *req, ValueDecl *cand,
3338+
ObjCSelector explicitObjCName) const {
3339+
// If the candidate we're considering is async, see if the requirement has
3340+
// an async alternate and try to match against that instead.
3341+
if (hasAsync(cand))
3342+
if (auto asyncAltReq = getAsyncAlternative(req))
3343+
return matchesImpl(asyncAltReq, cand, explicitObjCName);
3344+
3345+
return matchesImpl(req, cand, explicitObjCName);
3346+
}
3347+
32833348
void diagnoseOutcome(MatchOutcome outcome, ValueDecl *req, ValueDecl *cand,
32843349
ObjCSelector explicitObjCName) {
32853350
auto reqObjCName = *req->getObjCRuntimeName();
@@ -3333,6 +3398,22 @@ class ObjCImplementationChecker {
33333398
getCategoryName(cand->getDeclContext()->
33343399
getImplementedObjCContext()));
33353400
return;
3401+
3402+
case MatchOutcome::WrongDeclKind:
3403+
diagnose(cand, diag::objc_implementation_wrong_decl_kind,
3404+
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
3405+
return;
3406+
3407+
case MatchOutcome::WrongType:
3408+
diagnose(cand, diag::objc_implementation_type_mismatch,
3409+
cand->getDescriptiveKind(), cand,
3410+
getMemberType(cand), getMemberType(req));
3411+
return;
3412+
3413+
case MatchOutcome::WrongWritability:
3414+
diagnose(cand, diag::objc_implementation_must_be_settable,
3415+
cand->getDescriptiveKind(), cand, req->getDescriptiveKind());
3416+
return;
33363417
}
33373418

33383419
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)