Skip to content

Commit f90827e

Browse files
author
Itai Ferber
committed
Codable: excluded vars shouldn’t need explicit val
Properties of Codable types which are optional and excluded via the CodingKeys enum should not require an explicit nil assignment, since in all other cases, optional vars get a default value of nil.
1 parent 12841a9 commit f90827e

File tree

3 files changed

+149
-1
lines changed

3 files changed

+149
-1
lines changed

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,22 @@ validateCodingKeysEnum(TypeChecker &tc, EnumDecl *codingKeysDecl,
244244
if (!properties.empty() &&
245245
proto->isSpecificProtocol(KnownProtocolKind::Decodable)) {
246246
for (auto it = properties.begin(); it != properties.end(); ++it) {
247-
if (it->second->getParentInitializer() != nullptr) {
247+
auto *varDecl = it->second;
248+
249+
// Optional vars (not lets!) have an implicit default value of nil.
250+
if (!varDecl->isLet()) {
251+
if (!varDecl->hasType())
252+
tc.validateDecl(varDecl);
253+
254+
if (varDecl->hasType()) {
255+
auto varTypeDecl = varDecl->getType()->getAnyNominal();
256+
if (varTypeDecl == tc.Context.getOptionalDecl() ||
257+
varTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl())
258+
continue;
259+
}
260+
}
261+
262+
if (varDecl->getParentInitializer() != nullptr) {
248263
// Var has a default value.
249264
continue;
250265
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
class ClassWithNonExcludedLetMembers : Codable { // expected-error {{class 'ClassWithNonExcludedLetMembers' has no initializers}}
4+
// expected-error@-1 {{type 'ClassWithNonExcludedLetMembers' does not conform to protocol 'Decodable'}}
5+
// expected-error@-2 {{type 'ClassWithNonExcludedLetMembers' does not conform to protocol 'Encodable'}}
6+
7+
// Optional `let`s do not get an implicit nil assignment.
8+
let p1: String? // expected-note {{stored property 'p1' without initial value prevents synthesized initializers}}
9+
let p2: String! // expected-note {{stored property 'p2' without initial value prevents synthesized initializers}}
10+
11+
// AnyHashable does not conform to Codable.
12+
let p3: AnyHashable? // expected-note {{stored property 'p3' without initial value prevents synthesized initializers}}
13+
// expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'AnyHashable?' does not conform to 'Decodable'}}
14+
// expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'AnyHashable?' does not conform to 'Encodable'}}
15+
let p4: AnyHashable? // expected-note {{stored property 'p4' without initial value prevents synthesized initializers}}
16+
// expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'AnyHashable?' does not conform to 'Decodable'}}
17+
// expected-note@-2 {{cannot automatically synthesize 'Encodable' because 'AnyHashable?' does not conform to 'Encodable'}}
18+
}
19+
20+
class ClassWithExcludedLetMembers : Codable { // expected-error {{class 'ClassWithExcludedLetMembers' has no initializers}}
21+
// expected-error@-1 {{type 'ClassWithExcludedLetMembers' does not conform to protocol 'Decodable'}}
22+
23+
// Optional `let`s do not get an implicit nil assignment.
24+
let p1: String? // expected-note {{stored property 'p1' without initial value prevents synthesized initializers}}
25+
let p2: String! // expected-note {{stored property 'p2' without initial value prevents synthesized initializers}}
26+
27+
// AnyHashable does not conform to Codable.
28+
let p3: AnyHashable? // expected-note {{stored property 'p3' without initial value prevents synthesized initializers}}
29+
// expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'p3' does not have a matching CodingKey and does not have a default value}}
30+
let p4: AnyHashable? // expected-note {{stored property 'p4' without initial value prevents synthesized initializers}}
31+
// expected-note@-1 {{cannot automatically synthesize 'Decodable' because 'p4' does not have a matching CodingKey and does not have a default value}}
32+
33+
// Explicitly exclude non-Codable properties.
34+
enum CodingKeys : String, CodingKey {
35+
case p1, p2
36+
}
37+
}
38+
39+
class ClassWithNonExcludedVarMembers : Codable { // expected-error {{type 'ClassWithNonExcludedVarMembers' does not conform to protocol 'Decodable'}}
40+
// expected-error@-1 {{type 'ClassWithNonExcludedVarMembers' does not conform to protocol 'Encodable'}}
41+
42+
var p1: String?
43+
var p2: String!
44+
45+
// AnyHashable does not conform to Codable.
46+
var p3: AnyHashable? // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable?' does not conform to 'Decodable'}}
47+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable?' does not conform to 'Encodable'}}
48+
var p4: AnyHashable! // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable!' does not conform to 'Decodable'}}
49+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable!' does not conform to 'Encodable'}}
50+
}
51+
52+
class ClassWithExcludedVarMembers : Codable {
53+
var p1: String?
54+
var p2: String!
55+
56+
// AnyHashable does not conform to Codable.
57+
var p3: AnyHashable?
58+
var p4: AnyHashable!
59+
60+
// Explicitly exclude non-Codable properties.
61+
enum CodingKeys : String, CodingKey {
62+
case p1, p2
63+
}
64+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
struct StructWithNonExcludedLetMembers : Codable { // expected-error {{type 'StructWithNonExcludedLetMembers' does not conform to protocol 'Decodable'}}
4+
// expected-error@-1 {{type 'StructWithNonExcludedLetMembers' does not conform to protocol 'Encodable'}}
5+
6+
// Suppress the memberwise initializer. Optional `let`s do not get an implicit nil assignment.
7+
init() {}
8+
9+
let p1: String?
10+
let p2: String!
11+
12+
// AnyHashable does not conform to Codable.
13+
let p3: AnyHashable? // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable?' does not conform to 'Decodable'}}
14+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable?' does not conform to 'Encodable'}}
15+
let p4: AnyHashable! // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable!' does not conform to 'Decodable'}}
16+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable!' does not conform to 'Encodable'}}
17+
}
18+
19+
struct StructWithExcludedLetMembers : Codable { // expected-error {{type 'StructWithExcludedLetMembers' does not conform to protocol 'Decodable'}}
20+
21+
// Suppress the memberwise initializer. Optional `let`s do not get an implicit nil assignment.
22+
init() {}
23+
24+
let p1: String?
25+
let p2: String!
26+
27+
// AnyHashable does not conform to Codable.
28+
let p3: AnyHashable? // expected-note {{cannot automatically synthesize 'Decodable' because 'p3' does not have a matching CodingKey and does not have a default value}}
29+
let p4: AnyHashable! // expected-note {{cannot automatically synthesize 'Decodable' because 'p4' does not have a matching CodingKey and does not have a default value}}
30+
31+
// Explicitly exclude non-Codable properties.
32+
enum CodingKeys : String, CodingKey {
33+
case p1, p2
34+
}
35+
}
36+
37+
struct StructWithNonExcludedVarMembers : Codable { // expected-error {{type 'StructWithNonExcludedVarMembers' does not conform to protocol 'Decodable'}}
38+
// expected-error@-1 {{type 'StructWithNonExcludedVarMembers' does not conform to protocol 'Encodable'}}
39+
40+
// Suppress the memberwise initializer.
41+
init() {}
42+
43+
var p1: String?
44+
var p2: String!
45+
46+
// AnyHashable does not conform to Codable.
47+
var p3: AnyHashable? // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable?' does not conform to 'Decodable'}}
48+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable?' does not conform to 'Encodable'}}
49+
var p4: AnyHashable! // expected-note {{cannot automatically synthesize 'Decodable' because 'AnyHashable!' does not conform to 'Decodable'}}
50+
// expected-note@-1 {{cannot automatically synthesize 'Encodable' because 'AnyHashable!' does not conform to 'Encodable'}}
51+
}
52+
53+
struct StructWithExcludedVarMembers : Codable {
54+
55+
// Suppress the memberwise initializer.
56+
init() {}
57+
58+
var p1: String?
59+
var p2: String!
60+
61+
// AnyHashable does not conform to Codable.
62+
var p3: AnyHashable?
63+
var p4: AnyHashable!
64+
65+
// Explicitly exclude non-Codable properties.
66+
enum CodingKeys : String, CodingKey {
67+
case p1, p2
68+
}
69+
}

0 commit comments

Comments
 (0)