Skip to content

Commit 38df1c0

Browse files
committed
Include parent contexts in search for protocol extension contexts.
The previous check excluded nested functions that took and returned static Self. e.g. protocol P {} extension P { func foo() -> Self { func bar() -> Self { return self } return bar() } } Instead, search up the decl context chain until we find a protocol extension context.
1 parent 1c04dd1 commit 38df1c0

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

lib/Sema/TypeCheckDecl.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4047,20 +4047,23 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
40474047
if (simpleRepr->getIdentifier() != TC.Context.Id_Self)
40484048
return false;
40494049

4050+
// 'Self' in protocol extensions is not dynamic 'Self'.
4051+
DeclContext *dc = func->getDeclContext();
4052+
for (auto parentDC = dc; !parentDC->isModuleScopeContext();
4053+
parentDC = parentDC->getParent()) {
4054+
if (parentDC->getAsProtocolExtensionContext()) {
4055+
return false;
4056+
}
4057+
}
4058+
40504059
// Dynamic 'Self' is only permitted on methods.
4051-
auto dc = func->getDeclContext();
40524060
if (!dc->isTypeContext()) {
40534061
TC.diagnose(simpleRepr->getIdLoc(), diag::dynamic_self_non_method,
40544062
dc->isLocalContext());
40554063
simpleRepr->setInvalid();
40564064
return true;
40574065
}
40584066

4059-
// 'Self' in protocol extensions is not dynamic 'Self'.
4060-
if (dc->getAsProtocolExtensionContext()) {
4061-
return false;
4062-
}
4063-
40644067
// 'Self' is only a dynamic self on class methods and
40654068
// protocol requirements.
40664069
auto declaredType = dc->getDeclaredTypeOfContext();

test/decl/func/dynamic_self.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ protocol P0 {
3535
func g(_ ds: Self) // okay
3636
}
3737

38+
extension P0 {
39+
func h() -> Self { // okay
40+
func g(_ t : Self) -> Self { // okay
41+
return t
42+
}
43+
return g(self)
44+
}
45+
}
46+
47+
protocol P1: class {
48+
func f() -> Self // okay
49+
50+
func g(_ ds: Self) // okay
51+
}
52+
53+
extension P1 {
54+
func h() -> Self { // okay
55+
func g(_ t : Self) -> Self { // okay
56+
return t
57+
}
58+
return g(self)
59+
}
60+
}
61+
3862
// ----------------------------------------------------------------------------
3963
// The 'self' type of a Self method is based on Self
4064
class C1 {

0 commit comments

Comments
 (0)