Skip to content

Commit 196fe68

Browse files
authored
Merge pull request #11854 from itaiferber/codable-implicit-nil-values
Codable synthesis: excluded vars shouldn’t need explicit value assignments
2 parents 80c7d1e + f90827e commit 196fe68

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)