Skip to content

Commit 7d8c696

Browse files
authored
Merge pull request #12495 from gregomni/695
[Sema] Disallow override of dynamic Self return with non-dynamic.
2 parents ee7a062 + 7073eb1 commit 7d8c696

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,9 @@ ERROR(override_ownership_mismatch,none,
18851885
"cannot override %select{strong|weak|unowned|unowned(unsafe)}0 property "
18861886
"with %select{strong|weak|unowned|unowned(unsafe)}1 property",
18871887
(/*Ownership*/unsigned, /*Ownership*/unsigned))
1888+
ERROR(override_dynamic_self_mismatch,none,
1889+
"cannot override a Self return type with a non-Self return type",
1890+
())
18881891
ERROR(override_class_declaration_in_extension,none,
18891892
"cannot override a non-dynamic class declaration from an extension",
18901893
())

lib/Sema/TypeCheckDecl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6086,6 +6086,19 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
60866086
}
60876087
}
60886088

6089+
// If a super method returns Self, and the subclass overrides it to
6090+
// instead return the subclass type, complain.
6091+
// This case gets this far because the type matching above specifically
6092+
// strips out dynamic self via replaceCovariantResultType(), and that
6093+
// is helpful in several cases - just not this one.
6094+
if (decl->getASTContext().isSwiftVersionAtLeast(5) &&
6095+
matchDecl->getInterfaceType()->hasDynamicSelfType() &&
6096+
!decl->getInterfaceType()->hasDynamicSelfType() &&
6097+
!classDecl->isFinal()) {
6098+
TC.diagnose(decl, diag::override_dynamic_self_mismatch);
6099+
TC.diagnose(matchDecl, diag::overridden_here);
6100+
}
6101+
60896102
// Check that the override has the required access level.
60906103
// Overrides have to be at least as accessible as what they
60916104
// override, except:

test/Compatibility/self.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 4
2+
3+
// SR-695
4+
// in version 4 and earlier all of these should build with no diagnostic
5+
class Mario {
6+
func getFriend() -> Self { return self }
7+
func getEnemy() -> Mario { return self }
8+
}
9+
class SuperMario : Mario {
10+
override func getFriend() -> SuperMario {
11+
return SuperMario()
12+
}
13+
override func getEnemy() -> Self { return self }
14+
}
15+
final class FinalMario : Mario {
16+
override func getFriend() -> FinalMario {
17+
return FinalMario()
18+
}
19+
}

test/type/self.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
22

33
struct S0<T> {
44
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'S0'?}}{{21-25=S0}}
@@ -25,3 +25,21 @@ extension X {
2525
extension X.Inner {
2626
func foo(_ other: Self) { } // expected-error{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'X.Inner'?}}{{21-25=X.Inner}}
2727
}
28+
29+
// SR-695
30+
class Mario {
31+
func getFriend() -> Self { return self } // expected-note{{overridden declaration is here}}
32+
func getEnemy() -> Mario { return self }
33+
}
34+
class SuperMario : Mario {
35+
override func getFriend() -> SuperMario { // expected-error{{cannot override a Self return type with a non-Self return type}}
36+
return SuperMario()
37+
}
38+
override func getEnemy() -> Self { return self }
39+
}
40+
final class FinalMario : Mario {
41+
override func getFriend() -> FinalMario {
42+
return FinalMario()
43+
}
44+
}
45+

0 commit comments

Comments
 (0)