Skip to content

Commit bf8e50c

Browse files
committed
Sema: Consolidate diagnostics for invalid usage of DynamicSelfType
1 parent 0a9e1c2 commit bf8e50c

File tree

6 files changed

+91
-105
lines changed

6 files changed

+91
-105
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,19 +2576,19 @@ NOTE(missing_member_type_conformance_prevents_synthesis, none,
25762576
ERROR(dynamic_self_non_method,none,
25772577
"%select{global|local}0 function cannot return 'Self'", (bool))
25782578

2579-
ERROR(self_in_nominal,none,
2580-
"'Self' is only available in a protocol or as the result of a "
2581-
"method in a class; did you mean '%0'?", (StringRef))
2582-
ERROR(self_in_alias,none,
2583-
"'Self' is not available in a typealias", ())
2584-
ERROR(self_in_mutable_property,none,
2585-
"'Self' is not available as the type of a mutable property", ())
2586-
ERROR(self_in_mutable_subscript,none,
2587-
"'Self' is not available as the type of a mutable subscript", ())
2588-
ERROR(self_in_parameter,none,
2589-
"'Self' cannot be the type of a function argument in a class", ())
2590-
ERROR(self_in_nested_return,none,
2591-
"'Self' can only appear at the top level of a method result type", ())
2579+
ERROR(dynamic_self_invalid,none,
2580+
"covariant 'Self' can only appear as the type of a property, subscript or method result; "
2581+
"did you mean '%0'?", (StringRef))
2582+
ERROR(dynamic_self_in_mutable_property,none,
2583+
"mutable property cannot have covariant 'Self' type", ())
2584+
ERROR(dynamic_self_in_mutable_subscript,none,
2585+
"mutable subscript cannot have covariant 'Self' type", ())
2586+
ERROR(dynamic_self_invalid_property,none,
2587+
"covariant 'Self' can only appear at the top level of property type", ())
2588+
ERROR(dynamic_self_invalid_subscript,none,
2589+
"covariant 'Self' can only appear at the top level of subscript element type", ())
2590+
ERROR(dynamic_self_invalid_method,none,
2591+
"covariant 'Self' can only appear at the top level of method result type", ())
25922592

25932593
//------------------------------------------------------------------------------
25942594
// MARK: Type Check Attributes

lib/Sema/TypeCheckDecl.cpp

Lines changed: 44 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,6 +2181,32 @@ static void checkProtocolSelfRequirements(ProtocolDecl *proto,
21812181
});
21822182
}
21832183

2184+
/// For now, DynamicSelfType can only appear at the top level of a
2185+
/// function result type, possibly wrapped in an optional type.
2186+
///
2187+
/// In the future, we could generalize it to allow it in any
2188+
/// covariant position, so that for example a class method could
2189+
/// return '() -> Self'.
2190+
static void checkDynamicSelfType(ValueDecl *decl, Type type) {
2191+
if (!type->hasDynamicSelfType())
2192+
return;
2193+
2194+
if (auto objectTy = type->getOptionalObjectType())
2195+
type = objectTy;
2196+
2197+
if (type->is<DynamicSelfType>())
2198+
return;
2199+
2200+
if (isa<FuncDecl>(decl))
2201+
decl->diagnose(diag::dynamic_self_invalid_method);
2202+
else if (isa<VarDecl>(decl))
2203+
decl->diagnose(diag::dynamic_self_invalid_property);
2204+
else {
2205+
assert(isa<SubscriptDecl>(decl));
2206+
decl->diagnose(diag::dynamic_self_invalid_subscript);
2207+
}
2208+
}
2209+
21842210
namespace {
21852211
class DeclChecker : public DeclVisitor<DeclChecker> {
21862212
public:
@@ -2224,31 +2250,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
22242250
}
22252251
}
22262252

2227-
bool isDynamicSelf(Type Ty) {
2228-
return Ty->lookThroughAllOptionalTypes()->hasDynamicSelfType();
2229-
}
2230-
2231-
bool isDeclaredInClass(Decl *decl) {
2232-
return decl->getDeclContext()->getSelfClassDecl() != nullptr;
2233-
}
2234-
2235-
/// diagnoseSelfTypedParameters()
2236-
/// Diagnose instances of (Dynamic)Self as the type of a function arugument.
2237-
void diagnoseSelfTypedParameters(Type Ty, SourceLoc Loc, int level = 0) {
2238-
if (auto func = dyn_cast<FunctionType>(Ty->getCanonicalType())) {
2239-
for (auto &param : func->getParams()) {
2240-
if (isDynamicSelf(param.getParameterType())) {
2241-
TC.diagnose(Loc, diag::self_in_parameter);
2242-
diagnoseSelfTypedParameters(param.getParameterType(), Loc, level + 1);
2243-
}
2244-
}
2245-
if (Type returnTy = func->getResult()) {
2246-
if (level > 0 && isDynamicSelf(returnTy))
2247-
TC.diagnose(Loc, diag::self_in_nested_return);
2248-
diagnoseSelfTypedParameters(returnTy, Loc, level + 1);
2249-
}
2250-
}
2251-
}
22522253

22532254
//===--------------------------------------------------------------------===//
22542255
// Visit Methods.
@@ -2372,6 +2373,15 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
23722373

23732374
triggerAccessorSynthesis(TC, VD);
23742375

2376+
if (VD->getDeclContext()->getSelfClassDecl()) {
2377+
checkDynamicSelfType(VD, VD->getValueInterfaceType());
2378+
2379+
if (VD->getValueInterfaceType()->hasDynamicSelfType() &&
2380+
VD->isSettable(nullptr)) {
2381+
VD->diagnose(diag::dynamic_self_in_mutable_property);
2382+
}
2383+
}
2384+
23752385
// FIXME: Temporary hack until capture computation has been request-ified.
23762386
if (VD->getDeclContext()->isLocalContext()) {
23772387
VD->visitExpectedOpaqueAccessors([&](AccessorKind kind) {
@@ -2625,11 +2635,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26252635
TC.checkParameterAttributes(SD->getIndices());
26262636
TC.checkDefaultArguments(SD->getIndices(), SD);
26272637

2628-
if (SD->isSettable() && isDynamicSelf(SD->getElementInterfaceType()))
2629-
TC.diagnose(SD->getLoc(), diag::self_in_mutable_subscript);
2638+
if (SD->getDeclContext()->getSelfClassDecl()) {
2639+
checkDynamicSelfType(SD, SD->getValueInterfaceType());
26302640

2631-
diagnoseSelfTypedParameters(SD->getElementInterfaceType(),
2632-
SD->getElementTypeLoc().getLoc());
2641+
if (SD->getValueInterfaceType()->hasDynamicSelfType() &&
2642+
SD->isSettable()) {
2643+
SD->diagnose(diag::dynamic_self_in_mutable_subscript);
2644+
}
2645+
}
26332646
}
26342647

26352648
void visitTypeAliasDecl(TypeAliasDecl *TAD) {
@@ -2639,12 +2652,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26392652
TC.checkDeclAttributes(TAD);
26402653

26412654
checkAccessControl(TC, TAD);
2642-
2643-
TypeLoc &TyLoc = TAD->getUnderlyingTypeLoc();
2644-
if (isDynamicSelf(TyLoc.getType()))
2645-
TC.diagnose(TyLoc.getLoc(), diag::self_in_alias);
2646-
2647-
diagnoseSelfTypedParameters(TyLoc.getType(), TyLoc.getLoc());
26482655
}
26492656

26502657
void visitOpaqueTypeDecl(OpaqueTypeDecl *OTD) {
@@ -3106,14 +3113,6 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31063113
void visitVarDecl(VarDecl *VD) {
31073114
// Delay type-checking on VarDecls until we see the corresponding
31083115
// PatternBindingDecl.
3109-
3110-
if (isDeclaredInClass(VD)) {
3111-
if (VD->isSettable(nullptr) && isDynamicSelf(VD->getValueInterfaceType()))
3112-
TC.diagnose(VD->getLoc(), diag::self_in_mutable_property);
3113-
else
3114-
diagnoseSelfTypedParameters(VD->getValueInterfaceType(),
3115-
VD->getTypeLoc().getLoc());
3116-
}
31173116
}
31183117

31193118
/// Determine whether the given declaration requires a definition.
@@ -3195,31 +3194,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31953194

31963195
checkExplicitAvailability(FD);
31973196

3198-
if (isDeclaredInClass(FD)) {
3199-
for (auto *Param : *FD->getParameters()) {
3200-
TypeLoc TyLoc = Param->getTypeLoc();
3201-
SourceLoc Loc = TyLoc.hasLocation() ? TyLoc.getLoc() : Param->getLoc();
3202-
if (isDynamicSelf(Param->getInterfaceType()))
3203-
TC.diagnose(Loc, diag::self_in_parameter);
3204-
else
3205-
diagnoseSelfTypedParameters(Param->getInterfaceType(), Loc, 1);
3206-
}
3207-
3208-
auto ResultTy = FD->getResultInterfaceType();
3209-
3210-
// For now, DynamicSelfType can only appear at the top level of a
3211-
// function result type, possibly wrapped in an optional type.
3212-
if (ResultTy->hasDynamicSelfType()) {
3213-
if (auto ObjectTy = ResultTy->getOptionalObjectType())
3214-
ResultTy = ObjectTy;
3215-
if (!ResultTy->is<DynamicSelfType>()) {
3216-
auto loc = FD->getBodyResultTypeLoc().getLoc();
3217-
if (loc.isInvalid())
3218-
loc = FD->getLoc();
3219-
TC.diagnose(loc, diag::self_in_nested_return);
3220-
}
3221-
}
3222-
}
3197+
if (FD->getDeclContext()->getSelfClassDecl())
3198+
checkDynamicSelfType(FD, FD->getResultInterfaceType());
32233199
}
32243200

32253201
void visitModuleDecl(ModuleDecl *) { }

lib/Sema/TypeCheckType.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ static Type diagnoseUnknownType(TypeResolution resolution,
10791079

10801080
// Produce a Fix-It replacing 'Self' with the nominal type name.
10811081
auto name = getDeclNameFromContext(dc, nominal);
1082-
diags.diagnose(comp->getIdLoc(), diag::self_in_nominal, name)
1082+
diags.diagnose(comp->getIdLoc(), diag::dynamic_self_invalid, name)
10831083
.fixItReplace(comp->getIdLoc(), name);
10841084

10851085
auto type = resolution.mapTypeIntoContext(
@@ -1240,18 +1240,28 @@ static SelfTypeKind getSelfTypeKind(DeclContext *dc,
12401240
if (!typeDC->getSelfClassDecl())
12411241
return SelfTypeKind::StaticSelf;
12421242

1243-
// In local functions inside classes, 'Self' is the DynamicSelfType and can
1244-
// be used anywhere.
1245-
if (dc->isLocalContext())
1246-
return SelfTypeKind::DynamicSelf;
1247-
12481243
// In class methods, 'Self' is the DynamicSelfType and can only appear in
12491244
// the return type.
12501245
switch (options.getBaseContext()) {
12511246
case TypeResolverContext::FunctionResult:
12521247
case TypeResolverContext::PatternBindingDecl:
12531248
return SelfTypeKind::DynamicSelf;
1249+
case TypeResolverContext::AbstractFunctionDecl:
1250+
case TypeResolverContext::SubscriptDecl:
1251+
case TypeResolverContext::TypeAliasDecl:
1252+
case TypeResolverContext::GenericTypeAliasDecl:
1253+
// When checking a function or subscript parameter list, we have to go up
1254+
// one level to determine if we're in a local context or not.
1255+
if (dc->getParent()->isLocalContext())
1256+
return SelfTypeKind::DynamicSelf;
1257+
1258+
return SelfTypeKind::InvalidSelf;
12541259
default:
1260+
// In local functions inside classes, 'Self' is the DynamicSelfType and can
1261+
// be used anywhere.
1262+
if (dc->isLocalContext())
1263+
return SelfTypeKind::DynamicSelf;
1264+
12551265
return SelfTypeKind::InvalidSelf;
12561266
}
12571267
}

test/decl/ext/generic.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ extension Array where Element == String { }
149149
extension GenericClass : P3 where T : P3 { }
150150

151151
extension GenericClass where Self : P3 { }
152-
// expected-error@-1{{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'GenericClass'?}} {{30-34=GenericClass}}
152+
// expected-error@-1{{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'GenericClass'?}} {{30-34=GenericClass}}
153153
// expected-error@-2{{'GenericClass<T>' in conformance requirement does not refer to a generic parameter or associated type}}
154154

155155
protocol P4 {

test/decl/func/dynamic_self.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ enum E0 {
2424
class C0 {
2525
func f() -> Self { } // okay
2626

27-
func g(_ ds: Self) { } // expected-error{{'Self' cannot be the type of a function argument in a class}}
27+
func g(_ ds: Self) { } // expected-error{{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'C0'?}}
2828

29-
func h(_ ds: Self) -> Self { } // expected-error{{'Self' cannot be the type of a function argument in a class}}
29+
func h(_ ds: Self) -> Self { } // expected-error{{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'C0'?}}
3030
}
3131

3232
protocol P0 {

test/type/self.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ struct S0<T> {
55
}
66

77
class C0<T> {
8-
func foo(_ other: Self) { } // expected-error{{'Self' cannot be the type of a function argument in a class}}
8+
func foo(_ other: Self) { } // expected-error{{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'C0'?}}
99
}
1010

1111
enum E0<T> {
@@ -47,15 +47,15 @@ final class FinalMario : Mario {
4747

4848
class A<T> {
4949
typealias _Self = Self
50-
// expected-error@-1 {{'Self' is only available in a protocol or as the result of a method in a class; did you mean 'A'?}}
50+
// expected-error@-1 {{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'A'?}}
5151
let b: Int
5252
required init(a: Int) {
5353
print("\(Self.self).\(#function)")
5454
Self.y()
5555
b = a
5656
}
5757
static func z(n: Self? = nil) {
58-
// expected-error@-1 {{'Self' cannot be the type of a function argument in a class}}
58+
// expected-error@-1 {{covariant 'Self' can only appear as the type of a property, subscript or method result; did you mean 'A'?}}
5959
print("\(Self.self).\(#function)")
6060
}
6161
class func y() {
@@ -80,12 +80,11 @@ class A<T> {
8080
let copy = Self.init(a: 11)
8181
return copy
8282
}
83-
subscript (i: Int) -> Self { // expected-error {{'Self' is not available as the type of a mutable subscript}}
83+
subscript (i: Int) -> Self { // expected-error {{mutable subscript cannot have covariant 'Self' type}}
8484
get {
8585
return Self.init(a: i)
8686
}
8787
set(newValue) {
88-
// expected-error@-1 {{'Self' cannot be the type of a function argument in a class}}
8988
}
9089
}
9190
}
@@ -122,38 +121,39 @@ class C {
122121

123122
func f() {
124123
func g(_: Self) {}
124+
let x: Self = self as! Self
125+
g(x)
126+
typealias _Self = Self
125127
}
126128
func g() {
127129
_ = Self.init() as? Self
128130
// expected-warning@-1 {{conditional cast from 'Self' to 'Self' always succeeds}}
129131
}
130132
func h(j: () -> Self) -> () -> Self {
131-
// expected-error@-1 {{'Self' cannot be the type of a function argument in a class}}
132-
// expected-error@-2 {{'Self' can only appear at the top level of a method result type}}
133+
// expected-error@-1 {{covariant 'Self' can only appear at the top level of method result type}}
133134
return { return self }
134135
}
135136
func i() -> (Self, Self) {}
136-
// expected-error@-1 {{'Self' can only appear at the top level of a method result type}}
137+
// expected-error@-1 {{covariant 'Self' can only appear at the top level of method result type}}
137138

138139
func j() -> Self.Type {}
139-
// expected-error@-1 {{'Self' can only appear at the top level of a method result type}}
140+
// expected-error@-1 {{covariant 'Self' can only appear at the top level of method result type}}
140141

141142
let p0: Self?
142-
var p1: Self? // expected-error {{'Self' is not available as the type of a mutable property}}
143-
// expected-error@-1 {{'Self' cannot be the type of a function argument in a class}}
143+
var p1: Self? // expected-error {{mutable property cannot have covariant 'Self' type}}
144144

145-
var prop: Self { // expected-error {{'Self' is not available as the type of a mutable property}}
145+
var prop: Self { // expected-error {{mutable property cannot have covariant 'Self' type}}
146146
get {
147147
return self
148148
}
149-
set (newValue) { // expected-error {{'Self' cannot be the type of a function argument in a class}}
149+
set (newValue) {
150150
}
151151
}
152-
subscript (i: Int) -> Self { // expected-error {{'Self' is not available as the type of a mutable subscript}}
152+
subscript (i: Int) -> Self { // expected-error {{mutable subscript cannot have covariant 'Self' type}}
153153
get {
154154
return self
155155
}
156-
set (newValue) { // expected-error {{'Self' cannot be the type of a function argument in a class}}
156+
set (newValue) {
157157
}
158158
}
159159
}

0 commit comments

Comments
 (0)