Skip to content

Commit 691802c

Browse files
committed
Sema: Fix override matching of inout and vararg parameters
First, if the base parameter is inout or vararg, the derived parameter must be too. Second, we do not allow covariant overrides of inout or vararg parameters. Fixes <https://bugs.swift.org/browse/SR-10231>.
1 parent da45361 commit 691802c

File tree

2 files changed

+53
-17
lines changed

2 files changed

+53
-17
lines changed

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -560,25 +560,37 @@ static bool parameterTypesMatch(const ValueDecl *derivedDecl,
560560
/*derivedSubs=*/None);
561561

562562
for (auto i : indices(baseParams->getArray())) {
563-
auto baseItfTy = baseParams->get(i)->getInterfaceType();
564-
auto baseParamTy =
565-
baseDecl->getAsGenericContext()->mapTypeIntoContext(baseItfTy);
566-
baseParamTy = baseParamTy.subst(subs);
567-
auto derivedParamTy = derivedParams->get(i)->getInterfaceType();
563+
auto *baseParam = baseParams->get(i);
564+
auto *derivedParam = derivedParams->get(i);
568565

569-
// Attempt contravariant match.
570-
if (baseParamTy->matchesParameter(derivedParamTy, matchMode))
571-
continue;
566+
// Make sure inout-ness and varargs match.
567+
if (baseParam->isInOut() != derivedParam->isInOut() ||
568+
baseParam->isVariadic() != derivedParam->isVariadic()) {
569+
return false;
570+
}
571+
572+
auto baseParamTy = baseParam->getInterfaceType();
573+
baseParamTy = baseParamTy.subst(subs);
574+
auto derivedParamTy = derivedParam->getInterfaceType();
572575

573-
// Try once more for a match, using the underlying type of an
574-
// IUO if we're allowing that.
575-
if (baseParams->get(i)
576-
->getAttrs()
577-
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>() &&
578-
matchMode.contains(TypeMatchFlags::AllowNonOptionalForIUOParam)) {
579-
baseParamTy = baseParamTy->getOptionalObjectType();
580-
if (baseParamTy->matches(derivedParamTy, matchMode))
576+
if (baseParam->isInOut() || baseParam->isVariadic()) {
577+
// Inout and vararg parameters must match exactly.
578+
if (baseParamTy->isEqual(derivedParamTy))
581579
continue;
580+
} else {
581+
// Attempt contravariant match.
582+
if (baseParamTy->matchesParameter(derivedParamTy, matchMode))
583+
continue;
584+
585+
// Try once more for a match, using the underlying type of an
586+
// IUO if we're allowing that.
587+
if (baseParam->getAttrs()
588+
.hasAttribute<ImplicitlyUnwrappedOptionalAttr>() &&
589+
matchMode.contains(TypeMatchFlags::AllowNonOptionalForIUOParam)) {
590+
baseParamTy = baseParamTy->getOptionalObjectType();
591+
if (baseParamTy->matches(derivedParamTy, matchMode))
592+
continue;
593+
}
582594
}
583595

584596
// If there is no match, then we're done.

test/decl/class/override.swift

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ class GenericSubscriptDerived : GenericSubscriptBase {
316316

317317

318318
// @escaping
319-
320319
class CallbackBase {
321320
func perform(handler: @escaping () -> Void) {} // expected-note * {{here}}
322321
func perform(optHandler: (() -> Void)?) {} // expected-note * {{here}}
@@ -339,6 +338,31 @@ class CallbackSubC : CallbackBase {
339338
override func perform(nonescapingHandler: @escaping () -> Void) {} // expected-error {{method does not override any method from its superclass}}
340339
}
341340

341+
// inout, varargs
342+
class HasFlagsBase {
343+
func modify(x: inout B) {} // expected-note 2{{potential overridden instance method 'modify(x:)' here}}
344+
func tweak(x: inout A) {} // expected-note 2{{potential overridden instance method 'tweak(x:)' here}}
345+
func collect(x: B...) {} // expected-note 2{{potential overridden instance method 'collect(x:)' here}}
346+
}
347+
348+
class HasFlagsDerivedGood : HasFlagsBase {
349+
override func modify(x: inout B) {}
350+
override func tweak(x: inout A) {}
351+
override func collect(x: B...) {}
352+
}
353+
354+
class HasFlagsDerivedBad1 : HasFlagsBase {
355+
override func modify(x: inout A) {} // expected-error {{method does not override any method from its superclass}}
356+
override func tweak(x: inout B) {} // expected-error {{method does not override any method from its superclass}}
357+
override func collect(x: A...) {} // expected-error {{method does not override any method from its superclass}}
358+
}
359+
360+
class HasFlagsDerivedBad2 : HasFlagsBase {
361+
override func modify(x: B) {} // expected-error {{method does not override any method from its superclass}}
362+
override func tweak(x: A) {} // expected-error {{method does not override any method from its superclass}}
363+
override func collect(x: [B]) {} // expected-error {{method does not override any method from its superclass}}
364+
}
365+
342366
// Issues with overrides of internal(set) and fileprivate(set) members
343367
public class BaseWithInternalSetter {
344368
public internal(set) var someValue: Int = 0

0 commit comments

Comments
 (0)