Skip to content

Commit 7c29aaf

Browse files
committed
Sema: Fix generics invariant violations in override checking
Override checking checks if the derived declaration's generic signature is compatible with the base, but it does this after doing a bunch of other checks which feed potentially invalid type parameters to generic signature queries. Now that the requirement machine is stricter about this kind of this, re-organize some code to get around this. Unfortunately this regresses a diagnostic, because we reject candidates with mismatched generic requirements earlier in the process.
1 parent 382f04a commit 7c29aaf

File tree

7 files changed

+87
-53
lines changed

7 files changed

+87
-53
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,10 +2708,6 @@ WARNING(override_swift3_objc_inference,Deprecation,
27082708
"override of %0 %1 from extension of %2 depends on deprecated "
27092709
"inference of '@objc'",
27102710
(DescriptiveDeclKind, DeclName, Identifier))
2711-
ERROR(override_method_different_generic_sig,none,
2712-
"overridden method %0 has generic signature %1 which is incompatible with "
2713-
"base method's generic signature %2; expected generic signature to be %3",
2714-
(DeclBaseName, StringRef, StringRef, StringRef))
27152711

27162712
// Inheritance
27172713
ERROR(duplicate_inheritance,none,

lib/AST/ASTContext.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5150,11 +5150,22 @@ ASTContext::getOverrideGenericSignature(const ValueDecl *base,
51505150
bool ASTContext::overrideGenericSignatureReqsSatisfied(
51515151
const ValueDecl *base, const ValueDecl *derived,
51525152
const OverrideGenericSignatureReqCheck direction) {
5153+
auto *baseCtx = base->getAsGenericContext();
5154+
auto *derivedCtx = derived->getAsGenericContext();
5155+
5156+
if (baseCtx->isGeneric() != derivedCtx->isGeneric())
5157+
return false;
5158+
5159+
if (baseCtx->isGeneric() &&
5160+
(baseCtx->getGenericParams()->size() !=
5161+
derivedCtx->getGenericParams()->size()))
5162+
return false;
5163+
51535164
auto sig = getOverrideGenericSignature(base, derived);
51545165
if (!sig)
51555166
return true;
51565167

5157-
auto derivedSig = derived->getAsGenericContext()->getGenericSignature();
5168+
auto derivedSig = derivedCtx->getGenericSignature();
51585169

51595170
switch (direction) {
51605171
case OverrideGenericSignatureReqCheck::BaseReqSatisfiedByDerived:

lib/Sema/CodeSynthesis.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,9 @@ computeDesignatedInitOverrideSignature(ASTContext &ctx,
541541
auto lookupConformanceFn =
542542
[&](CanType depTy, Type substTy,
543543
ProtocolDecl *proto) -> ProtocolConformanceRef {
544-
if (auto conf = subMap.lookupConformance(depTy, proto))
545-
return conf;
544+
if (depTy->getRootGenericParam()->getDepth() < superclassDepth)
545+
if (auto conf = subMap.lookupConformance(depTy, proto))
546+
return conf;
546547

547548
return ProtocolConformanceRef(proto);
548549
};
@@ -1125,9 +1126,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
11251126
continue;
11261127

11271128
auto type = swift::getMemberTypeForComparison(ctor, nullptr);
1128-
auto parentType = swift::getMemberTypeForComparison(superclassCtor, ctor);
1129-
1130-
if (isOverrideBasedOnType(ctor, type, superclassCtor, parentType)) {
1129+
if (isOverrideBasedOnType(ctor, type, superclassCtor)) {
11311130
alreadyDeclared = true;
11321131
break;
11331132
}

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,11 @@ areAccessorsOverrideCompatible(const AbstractStorageDecl *storage,
146146
}
147147

148148
bool swift::isOverrideBasedOnType(const ValueDecl *decl, Type declTy,
149-
const ValueDecl *parentDecl,
150-
Type parentDeclTy) {
149+
const ValueDecl *parentDecl) {
151150
auto genericSig =
152151
decl->getInnermostDeclContext()->getGenericSignatureOfContext();
153152

154153
auto canDeclTy = declTy->getCanonicalType(genericSig);
155-
auto canParentDeclTy = parentDeclTy->getCanonicalType(genericSig);
156154

157155
auto declIUOAttr = decl->isImplicitlyUnwrappedOptional();
158156
auto parentDeclIUOAttr = parentDecl->isImplicitlyUnwrappedOptional();
@@ -167,18 +165,33 @@ bool swift::isOverrideBasedOnType(const ValueDecl *decl, Type declTy,
167165
// We can still succeed with a subtype match later in
168166
// OverrideMatcher::match().
169167
if (decl->getDeclContext()->getSelfClassDecl()) {
170-
if (auto declGenericCtx = decl->getAsGenericContext()) {
168+
if (auto declCtx = decl->getAsGenericContext()) {
169+
auto *parentCtx = parentDecl->getAsGenericContext();
170+
171+
if (declCtx->isGeneric() != parentCtx->isGeneric())
172+
return false;
173+
174+
if (declCtx->isGeneric() &&
175+
(declCtx->getGenericParams()->size() !=
176+
parentCtx->getGenericParams()->size()))
177+
return false;
178+
171179
auto &ctx = decl->getASTContext();
172180
auto sig = ctx.getOverrideGenericSignature(parentDecl, decl);
173-
174181
if (sig &&
175-
declGenericCtx->getGenericSignature().getCanonicalSignature() !=
182+
declCtx->getGenericSignature().getCanonicalSignature() !=
176183
sig.getCanonicalSignature()) {
177184
return false;
178185
}
179186
}
180187
}
181188

189+
auto parentDeclTy = getMemberTypeForComparison(parentDecl, decl);
190+
if (parentDeclTy->hasError())
191+
return false;
192+
193+
auto canParentDeclTy = parentDeclTy->getCanonicalType(genericSig);
194+
182195
// If this is a constructor, let's compare only parameter types.
183196
if (isa<ConstructorDecl>(decl)) {
184197
// Within a protocol context, check for a failability mismatch.
@@ -285,6 +298,11 @@ static bool areOverrideCompatibleSimple(ValueDecl *decl,
285298
auto genParentDecl = parentDecl->getAsGenericContext();
286299
if (genDecl->isGeneric() != genParentDecl->isGeneric())
287300
return false;
301+
302+
if (genDecl->isGeneric() &&
303+
(genDecl->getGenericParams()->size() !=
304+
genParentDecl->getGenericParams()->size()))
305+
return false;
288306
}
289307

290308
// Factory initializers cannot be overridden.
@@ -908,13 +926,22 @@ SmallVector<OverrideMatch, 2> OverrideMatcher::match(
908926
(void)parentMethod;
909927
(void)parentStorage;
910928

911-
// Check whether the types are identical.
912-
auto parentDeclTy = getMemberTypeForComparison(parentDecl, decl);
913-
if (parentDeclTy->hasError())
914-
continue;
929+
// If the generic requirements don't match, don't try anything else below,
930+
// because it will compute an invalid interface type by applying malformed
931+
// substitutions.
932+
if (isClassOverride()) {
933+
using Direction = ASTContext::OverrideGenericSignatureReqCheck;
934+
if (decl->getAsGenericContext()) {
935+
if (!ctx.overrideGenericSignatureReqsSatisfied(
936+
parentDecl, decl, Direction::DerivedReqSatisfiedByBase)) {
937+
continue;
938+
}
939+
}
940+
}
915941

942+
// Check whether the types are identical.
916943
Type declTy = getDeclComparisonType();
917-
if (isOverrideBasedOnType(decl, declTy, parentDecl, parentDeclTy)) {
944+
if (isOverrideBasedOnType(decl, declTy, parentDecl)) {
918945
matches.push_back({parentDecl, true});
919946
continue;
920947
}
@@ -944,6 +971,7 @@ SmallVector<OverrideMatch, 2> OverrideMatcher::match(
944971
}
945972

946973
auto declFnTy = getDeclComparisonType()->getAs<AnyFunctionType>();
974+
auto parentDeclTy = getMemberTypeForComparison(parentDecl, decl);
947975
auto parentDeclFnTy = parentDeclTy->getAs<AnyFunctionType>();
948976
if (declFnTy && parentDeclFnTy) {
949977
auto paramsAndResultMatch = [=]() -> bool {
@@ -1102,26 +1130,6 @@ bool OverrideMatcher::checkOverride(ValueDecl *baseDecl,
11021130
emittedMatchError = true;
11031131
}
11041132

1105-
if (isClassOverride()) {
1106-
auto baseGenericCtx = baseDecl->getAsGenericContext();
1107-
auto derivedGenericCtx = decl->getAsGenericContext();
1108-
1109-
using Direction = ASTContext::OverrideGenericSignatureReqCheck;
1110-
if (baseGenericCtx && derivedGenericCtx) {
1111-
if (!ctx.overrideGenericSignatureReqsSatisfied(
1112-
baseDecl, decl, Direction::DerivedReqSatisfiedByBase)) {
1113-
auto newSig = ctx.getOverrideGenericSignature(baseDecl, decl);
1114-
diags.diagnose(decl, diag::override_method_different_generic_sig,
1115-
decl->getBaseName(),
1116-
derivedGenericCtx->getGenericSignature()->getAsString(),
1117-
baseGenericCtx->getGenericSignature()->getAsString(),
1118-
newSig->getAsString());
1119-
diags.diagnose(baseDecl, diag::overridden_here);
1120-
emittedMatchError = true;
1121-
}
1122-
}
1123-
}
1124-
11251133
// If we have an explicit ownership modifier and our parent doesn't,
11261134
// complain.
11271135
auto parentAttr =

lib/Sema/TypeChecker.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,7 @@ Type getMemberTypeForComparison(const ValueDecl *member,
12611261
/// Determine whether the given declaration is an override by comparing type
12621262
/// information.
12631263
bool isOverrideBasedOnType(const ValueDecl *decl, Type declTy,
1264-
const ValueDecl *parentDecl, Type parentDeclTy);
1264+
const ValueDecl *parentDecl);
12651265

12661266
/// Determine whether the given declaration is an operator defined in a
12671267
/// protocol. If \p type is not null, check specifically whether \p decl

test/attr/attr_override.swift

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift -swift-version 5
1+
// RUN: %target-typecheck-verify-swift -swift-version 5 -requirement-machine=verify
22

33
@override // expected-error {{'override' can only be specified on class members}} {{1-11=}} expected-error {{'override' is a declaration modifier, not an attribute}} {{1-2=}}
44
func virtualAttributeCanNotBeUsedInSource() {}
@@ -545,21 +545,21 @@ class SR_4206_DerivedConcrete_2<T>: SR_4206_BaseGeneric_2<T> {
545545
// Base class generic w/ method generic, derived class generic w/ method generic but different requirement
546546

547547
class SR_4206_BaseGeneric_3<T> {
548-
func foo<T>(arg: T) {} // expected-note {{overridden declaration is here}}
548+
func foo<T>(arg: T) {}
549549
}
550550

551551
class SR_4206_DerivedGeneric_3<T>: SR_4206_BaseGeneric_3<T> {
552-
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{overridden method 'foo' has generic signature <T, T where T : SR_4206_Protocol_1> which is incompatible with base method's generic signature <T, T>; expected generic signature to be <T, T>}}
552+
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
553553
}
554554

555555
// Base class not generic w/ method generic, derived class not generic w/ method generic but different requirement
556556

557557
class SR_4206_BaseConcrete_4 {
558-
func foo<T>(arg: T) {} // expected-note {{overridden declaration is here}}
558+
func foo<T>(arg: T) {}
559559
}
560560

561561
class SR_4206_DerivedConcrete_4: SR_4206_BaseConcrete_4 {
562-
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{overridden method 'foo' has generic signature <T where T : SR_4206_Protocol_1> which is incompatible with base method's generic signature <T>; expected generic signature to be <T>}}
562+
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
563563
}
564564

565565
// Base class not generic w/ method generic, derived class not generic w/ method generic but removed requirement
@@ -575,22 +575,22 @@ class SR_4206_DerivedConcrete_5: SR_4206_BaseConcrete_5 {
575575
// Base class not generic w/ method generic, derived class generic w/ method generic but different requirement
576576

577577
class SR_4206_BaseConcrete_6 {
578-
func foo<T: SR_4206_Protocol_2>(arg: T) {} // expected-note {{overridden declaration is here}}
578+
func foo<T: SR_4206_Protocol_2>(arg: T) {}
579579
}
580580

581581
class SR_4206_DerivedGeneric_6<T>: SR_4206_BaseConcrete_6 {
582-
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{overridden method 'foo' has generic signature <T, T where T : SR_4206_Protocol_1> which is incompatible with base method's generic signature <T where T : SR_4206_Protocol_2>; expected generic signature to be <T, T where T : SR_4206_Protocol_2>}}
582+
override func foo<T: SR_4206_Protocol_1>(arg: T) {} // expected-error {{method does not override any method from its superclass}}
583583
}
584584

585585
// Contextual where clauses on non-generic members
586586

587587
class SR_4206_Base_7<T> {
588-
func foo1() where T: SR_4206_Protocol_1 {} // expected-note {{overridden declaration is here}}
588+
func foo1() where T: SR_4206_Protocol_1 {}
589589
func foo2() where T: SR_4206_Protocol_1 {}
590590
}
591591

592592
class SR_4206_Derived_7<T>: SR_4206_Base_7<T> {
593-
override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{overridden method 'foo1' has generic signature <T where T : SR_4206_Protocol_2> which is incompatible with base method's generic signature <T where T : SR_4206_Protocol_1>; expected generic signature to be <T where T : SR_4206_Protocol_1>}}
593+
override func foo1() where T: SR_4206_Protocol_2 {} // expected-error {{method does not override any method from its superclass}}
594594

595595
override func foo2() {} // OK
596596
}
@@ -624,10 +624,10 @@ class SR_4206_Derived_9<T>: SR_4206_Base_9<T> {
624624
// Override with constraint on a non-inherited generic param
625625

626626
class SR_4206_Base_10<T> {
627-
func foo() where T: SR_4206_Protocol_1 {} // expected-note {{overridden declaration is here}}
627+
func foo() where T: SR_4206_Protocol_1 {}
628628
}
629629
class SR_4206_Derived_10<T, U>: SR_4206_Base_10<T> {
630-
override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{overridden method 'foo' has generic signature <T, U where U : SR_4206_Protocol_1> which is incompatible with base method's generic signature <T where T : SR_4206_Protocol_1>; expected generic signature to be <T, U where T : SR_4206_Protocol_1>}}
630+
override func foo() where U: SR_4206_Protocol_1 {} // expected-error {{method does not override any method from its superclass}}
631631
}
632632

633633
// Override with return type specialization
@@ -710,3 +710,19 @@ public extension SR_11740_Base where F: SR_11740_Q {
710710
extension SR_11740_Derived where F: SR_11740_P {
711711
public static func foo(_: A) {}
712712
}
713+
714+
// Make sure we don't crash on generic requirement mismatch
715+
protocol P3 {}
716+
717+
protocol P4 {
718+
associatedtype T
719+
}
720+
721+
class Base {
722+
func method<T: P3>(_: T) {}
723+
func method<T: P4>(_: T) where T.T : P3 {}
724+
}
725+
726+
class Derived: Base {
727+
override func method<T: P3>(_: T) {}
728+
}

test/decl/circularity.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,12 @@ open class G1<A> {
8484
class C3: G1<A>, P {
8585
// expected-error@-1 {{type 'C3' does not conform to protocol 'P'}}
8686
// expected-error@-2 {{cannot find type 'A' in scope}}
87+
// expected-note@-3 {{through reference here}}
8788
override func run(a: A) {}
8889
// expected-error@-1 {{method does not override any method from its superclass}}
90+
// expected-error@-2 {{circular reference}}
91+
// expected-note@-3 2 {{through reference here}}
92+
// expected-note@-4 {{while resolving type 'A'}}
8993
}
9094

9195
// Another case that triggers circular override checking.

0 commit comments

Comments
 (0)