Skip to content

Commit 103a821

Browse files
committed
Sema: Allow non-final classes to satisfy properties and subscripts with covariant Self
1 parent 1e0a9ca commit 103a821

File tree

7 files changed

+101
-59
lines changed

7 files changed

+101
-59
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4123,12 +4123,14 @@ struct SelfReferenceKind {
41234123
return SelfReferenceKind(false, false, false, false);
41244124
}
41254125

4126-
/// The type refers to 'Self', but only as the result type of a method.
4126+
/// The type refers to 'Self', but only as the type of a property or
4127+
/// the result type of a method/subscript.
41274128
static SelfReferenceKind Result() {
41284129
return SelfReferenceKind(true, false, false, false);
41294130
}
41304131

4131-
/// The type refers to 'Self', but only as the parameter type of a method.
4132+
/// The type refers to 'Self', but only as the parameter type
4133+
/// of a method/subscript.
41324134
static SelfReferenceKind Parameter() {
41334135
return SelfReferenceKind(false, true, false, false);
41344136
}

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,14 +1992,15 @@ NOTE(witness_self_weaken_same_type,none,
19921992
"consider weakening the same-type requirement %0 == %1 to a superclass "
19931993
"requirement", (Type, Type))
19941994
ERROR(witness_requires_dynamic_self,none,
1995-
"method %0 in non-final class %1 must return 'Self' to conform to "
1996-
"protocol %2",
1997-
(DeclName, Type, Type))
1995+
"%select{%error|method|property|subscript}0 %1 in non-final class %2 "
1996+
"must %select{%error|return|specify type|return}0 'Self' "
1997+
"to conform to protocol %3",
1998+
(RequirementKind, DeclName, Type, Type))
19981999
ERROR(witness_requires_class_implementation,none,
1999-
"method %0 in non-final class %1 cannot be implemented in a "
2000-
"protocol extension because it returns 'Self' and has associated type "
2001-
"requirements",
2002-
(DeclName, Type))
2000+
"%select{%error|method|%error|subscript}0 %1 in non-final class %2 "
2001+
"cannot be implemented in a protocol extension because it returns 'Self' "
2002+
"and has associated type requirements",
2003+
(RequirementKind, DeclName, Type))
20032004
ERROR(witness_not_accessible_proto,none,
20042005
"%select{initializer %1|method %1|%select{|setter for }2property %1"
20052006
"|subscript%select{| setter}2}0 must be declared "

lib/AST/Decl.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4965,12 +4965,13 @@ ProtocolDecl::findProtocolSelfReferences(const ValueDecl *value,
49654965
return ::findProtocolSelfReferences(this, type,
49664966
skipAssocTypes);
49674967
} else {
4968-
if (::findProtocolSelfReferences(this, type,
4969-
skipAssocTypes)) {
4970-
return SelfReferenceKind::Other();
4971-
}
4972-
return SelfReferenceKind::None();
4968+
assert(isa<VarDecl>(value));
4969+
4970+
return ::findProtocolSelfReferences(this, type,
4971+
skipAssocTypes);
49734972
}
4973+
4974+
return SelfReferenceKind::None();
49744975
}
49754976

49764977
bool ProtocolDecl::isAvailableInExistential(const ValueDecl *decl) const {

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,7 +2078,7 @@ static Type getRequirementTypeForDisplay(ModuleDecl *module,
20782078
return FunctionType::get(params, result, fnTy->getExtInfo());
20792079
}
20802080

2081-
return substType(type, /*result*/false);
2081+
return substType(type, /*result*/ true);
20822082
}
20832083

20842084
diag::RequirementKind
@@ -3343,41 +3343,36 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
33433343
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
33443344
});
33453345
} else if (selfKind.result) {
3346-
// The reference to Self occurs in the result type. A non-final class
3347-
// can satisfy this requirement with a method that returns Self.
3346+
// The reference to Self occurs in the result type of a method/subscript
3347+
// or the type of a property. A non-final class can satisfy this requirement
3348+
// by holding onto Self accordingly.
3349+
if (witness->getDeclContext()->getSelfClassDecl()) {
3350+
const bool hasDynamicSelfResult = [&] {
3351+
if (auto func = dyn_cast<AbstractFunctionDecl>(witness)) {
3352+
return func->hasDynamicSelfResult();
3353+
} else if (auto var = dyn_cast<VarDecl>(witness)) {
3354+
return var->getInterfaceType()->hasDynamicSelfType();
3355+
}
33483356

3349-
// If the function has a dynamic Self, it's okay.
3350-
if (auto func = dyn_cast<FuncDecl>(witness)) {
3351-
if (func->getDeclContext()->getSelfClassDecl() &&
3352-
!func->hasDynamicSelfResult()) {
3357+
return cast<SubscriptDecl>(witness)
3358+
->getElementInterfaceType()
3359+
->hasDynamicSelfType();
3360+
}();
3361+
3362+
if (!hasDynamicSelfResult) {
33533363
diagnoseOrDefer(requirement, false,
33543364
[witness, requirement](NormalProtocolConformance *conformance) {
33553365
auto proto = conformance->getProtocol();
33563366
auto &diags = proto->getASTContext().Diags;
33573367
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance,witness);
3358-
diags.diagnose(diagLoc,
3359-
diag::witness_requires_dynamic_self,
3368+
diags.diagnose(diagLoc, diag::witness_requires_dynamic_self,
3369+
getProtocolRequirementKind(requirement),
33603370
requirement->getName(),
33613371
conformance->getType(),
33623372
proto->getDeclaredInterfaceType());
33633373
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
33643374
});
33653375
}
3366-
3367-
// Constructors conceptually also have a dynamic Self
3368-
// return type, so they're okay.
3369-
} else if (!isa<ConstructorDecl>(witness)) {
3370-
diagnoseOrDefer(requirement, false,
3371-
[witness, requirement](NormalProtocolConformance *conformance) {
3372-
auto proto = conformance->getProtocol();
3373-
auto &diags = proto->getASTContext().Diags;
3374-
SourceLoc diagLoc = getLocForDiagnosingWitness(conformance, witness);
3375-
diags.diagnose(diagLoc, diag::witness_self_non_subtype,
3376-
proto->getDeclaredInterfaceType(),
3377-
requirement->getName(),
3378-
conformance->getType());
3379-
emitDeclaredHereIfNeeded(diags, diagLoc, witness);
3380-
});
33813376
}
33823377
} else if (selfKind.requirement) {
33833378
if (auto targetPair = getAdopteeSelfSameTypeConstraint(classDecl,
@@ -3413,8 +3408,8 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
34133408
// constraint that either the requirement not produce 'Self' in a
34143409
// covariant position, or the type of the requirement does not involve
34153410
// associated types.
3416-
if (auto func = dyn_cast<FuncDecl>(witness)) {
3417-
if (func->getDeclContext()->getExtendedProtocolDecl()) {
3411+
if (isa<FuncDecl>(witness) || isa<SubscriptDecl>(witness)) {
3412+
if (witness->getDeclContext()->getExtendedProtocolDecl()) {
34183413
auto selfKindWithAssocTypes = Proto->findProtocolSelfReferences(
34193414
requirement,
34203415
/*allowCovariantParameters=*/false,
@@ -3427,6 +3422,7 @@ void ConformanceChecker::checkNonFinalClassWitness(ValueDecl *requirement,
34273422
auto &diags = proto->getASTContext().Diags;
34283423
diags.diagnose(conformance->getLoc(),
34293424
diag::witness_requires_class_implementation,
3425+
getProtocolRequirementKind(requirement),
34303426
requirement->getName(),
34313427
conformance->getType());
34323428
diags.diagnose(witness, diag::decl_declared_here,

test/decl/protocol/conforms/inherited.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ protocol P1 {
55
func f1(_ x: Self?) -> Bool
66
}
77

8-
// Never inheritable: property with 'Self' in its signature.
8+
// Inheritable: property with 'Self' in its signature.
99
protocol P2 {
1010
var prop2: Self { get set }
1111
}
1212
protocol P2a {
1313
var prop2a: Self { get set }
1414
}
1515

16-
// Never inheritable: subscript with 'Self' in its result type.
16+
// Inheritable: subscript with 'Self' in its result type.
1717
protocol P3 {
1818
subscript (i: Int) -> Self { get }
1919
}
@@ -94,7 +94,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 {
9494
func f1(_ x: A?) -> Bool { return true }
9595

9696
// P2
97-
var prop2: A { // expected-error{{protocol 'P2' requirement 'prop2' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}}
97+
var prop2: A { // expected-error{{property 'prop2' in non-final class 'A' must specify type 'Self' to conform to protocol 'P2'}}
9898
get { return self }
9999
set {}
100100
}
@@ -106,7 +106,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 {
106106
}
107107

108108
// P3
109-
subscript (i: Int) -> A { // expected-error{{protocol 'P3' requirement 'subscript(_:)' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}}
109+
subscript (i: Int) -> A { // expected-error{{subscript 'subscript(_:)' in non-final class 'A' must return 'Self' to conform to protocol 'P3'}}
110110
get {
111111
return self
112112
}
@@ -145,7 +145,7 @@ class A : P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 {
145145
}
146146

147147
extension A: P2a, P5a, P10a {}
148-
// expected-error@-1 {{protocol 'P2a' requirement 'prop2a' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}}
148+
// expected-error@-1 {{property 'prop2a' in non-final class 'A' must specify type 'Self' to conform to protocol 'P2a'}}
149149
// expected-error@-2 {{method 'f5a()' in non-final class 'A' must return 'Self' to conform to protocol 'P5a'}}
150150
// expected-error@-3 {{protocol 'P10a' requirement 'f10a' cannot be satisfied by a non-final class ('A') because it uses 'Self' in a non-parameter, non-result type position}}
151151

test/decl/protocol/conforms/self.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ protocol P {
77
func returnsSelf() -> Self
88
func hasDefaultTakesT(_: T)
99
func returnsSelfTakesT(_: T) -> Self
10+
11+
subscript(_: T) -> Self { get }
1012
}
1113

1214
extension P {
@@ -21,19 +23,29 @@ extension P {
2123
func returnsSelfTakesT(_: T) -> Self { // expected-note {{'returnsSelfTakesT' declared here}}
2224
return self
2325
}
26+
27+
subscript(_: T) -> Self { self } // expected-note {{'subscript(_:)' declared here}}
2428
}
2529

2630
// This fails
27-
class Class : P {} // expected-error {{method 'returnsSelfTakesT' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}}
31+
class Class : P {}
32+
// expected-error@-1 {{method 'returnsSelfTakesT' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}}
33+
// expected-error@-2 {{subscript 'subscript(_:)' in non-final class 'Class' cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements}}
2834

2935
// This succeeds, because the class is final
3036
final class FinalClass : P {}
3137

32-
// This succeeds, because we're not using the default implementation
38+
// This succeeds, because we're not using the default implementations
3339
class NonFinalClass : P {
40+
// FIXME: An explicit type witness is necessary to avoid an unrelated
41+
// associated type inference bug.
42+
typealias T = Never
43+
3444
func returnsSelfTakesT(_: T) -> Self {
3545
return self
3646
}
47+
48+
subscript(_: T) -> Self { self }
3749
}
3850

3951
// Test for default implementation that comes from a constrained extension
Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,88 @@
11
// RUN: %target-typecheck-verify-swift
22

33
protocol P {
4+
var p: Self { get }
5+
// expected-note@-1{{protocol requires property 'p' with type 'Self'}}
6+
// expected-note@-2{{protocol requires property 'p' with type 'EError'}}
7+
// expected-note@-3{{protocol requires property 'p' with type 'SError'}}
8+
subscript() -> Self { get }
9+
// expected-note@-1{{protocol requires subscript with type '() -> Self'}}
10+
// expected-note@-2{{protocol requires subscript with type '() -> EError'}}
11+
// expected-note@-3{{protocol requires subscript with type '() -> SError'}}
412
func f() -> Self
513
// expected-note@-1{{protocol requires function 'f()' with type '() -> Self'}}
614
// expected-note@-2{{protocol requires function 'f()' with type '() -> EError'}}
715
// expected-note@-3{{protocol requires function 'f()' with type '() -> SError'}}
816
}
917

10-
// Error: Missing Self method in a class.
18+
func takesP(_: P) {} // OK
19+
20+
// Error: Missing witnesses.
1121
class W : P {} // expected-error{{type 'W' does not conform to protocol 'P'}}
1222

1323
// Okay: Self method in class.
1424
class X : P {
15-
func f() -> Self { return self }
25+
var p: Self { self }
26+
subscript() -> Self { self }
27+
func f() -> Self { self }
1628
}
1729

1830
class Y {
19-
func f() -> Self { return self }
31+
var p: Self { self }
32+
subscript() -> Self { self }
33+
func f() -> Self { self }
2034
}
2135

2236
class GX<T> : P {
23-
func f() -> Self { return self }
37+
var p: Self { self }
38+
subscript() -> Self { self }
39+
func f() -> Self { self }
2440
}
2541

2642
// Okay: dynamic Self method in superclass.
2743
class Z : Y, P { }
2844

29-
// Erro: Z2 conforms, but subclass would not
45+
// Error: Z2 conforms, but subclass would not.
3046
class Z2 : P {
31-
func f() -> Z2 { return self } // expected-error{{method 'f()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}}
47+
var p: Z2 { self } //expected-error{{property 'p' in non-final class 'Z2' must specify type 'Self' to conform to protocol 'P'}}
48+
subscript() -> Z2 { self } //expected-error{{subscript 'subscript()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}}
49+
func f() -> Z2 { self } // expected-error{{method 'f()' in non-final class 'Z2' must return 'Self' to conform to protocol 'P'}}
3250
}
3351

3452
// Okay: struct conforms by returning itself
3553
struct S : P {
36-
func f() -> S { return self }
54+
var p: S { self }
55+
subscript() -> S { self }
56+
func f() -> S { self }
3757
}
3858

3959
struct GS<T> : P {
40-
func f() -> GS { return self }
60+
var p: GS { self }
61+
subscript() -> GS { self }
62+
func f() -> GS { self }
4163
}
4264

4365
struct SError : P { // expected-error{{type 'SError' does not conform to protocol 'P'}}
44-
func f() -> Int { return 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
66+
var p: Int { 0 } // expected-note{{candidate has non-matching type 'Int'}}
67+
subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
68+
func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
4569
}
4670

4771
// Okay: enum conforms by returning itself
4872
enum E : P {
49-
func f() -> E { return self }
73+
var p: E { self }
74+
subscript() -> E { self }
75+
func f() -> E { self }
5076
}
5177

5278
enum GE<T> : P {
53-
func f() -> GE { return self }
79+
var p: GE { self }
80+
subscript() -> GE { self }
81+
func f() -> GE { self }
5482
}
5583

5684
enum EError : P { // expected-error{{type 'EError' does not conform to protocol 'P'}}
57-
func f() -> Int { return 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
85+
var p: Int { 0 } // expected-note{{candidate has non-matching type 'Int'}}
86+
subscript() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
87+
func f() -> Int { 0 } // expected-note{{candidate has non-matching type '() -> Int'}}
5888
}

0 commit comments

Comments
 (0)