Skip to content

Commit 33de34b

Browse files
authored
Merge pull request #13178 from DougGregor/coding-conditional-conformances
[Coding] Make Codable conformances for Optional and collections conditional.
2 parents 4f102c6 + 49f375c commit 33de34b

File tree

4 files changed

+40
-139
lines changed

4 files changed

+40
-139
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ CHANGELOG
2222
Swift 4.1
2323
---------
2424

25+
* [SE-0166][] / [SE-0143][]
26+
27+
The standard library now defines the conformances of `Optional`,
28+
`Array`, `Dictionary`, and `Set` to `Encodable` and `Decodable` as
29+
conditional conformances, available only when their type parameters
30+
conform to `Encodable` or `Decodable`, respectively.
31+
2532
* [SE-0188][]
2633

2734
Index types for most standard library collections now conform to `Hashable`.

lib/Sema/DerivedConformanceCodable.cpp

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,22 +98,7 @@ static CodableConformanceType typeConformsToCodable(TypeChecker &tc,
9898
// Implicitly unwrapped optionals need to be unwrapped;
9999
// ImplicitlyUnwrappedOptional does not need to conform to Codable directly
100100
// -- only its inner type does.
101-
if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl() ||
102-
// FIXME: Remove the following when conditional conformance lands.
103-
// Some generic types in the stdlib currently conform to Codable even
104-
// when the type they are generic on does not [Optional, Array, Set,
105-
// Dictionary]. For synthesizing conformance, we don't want to
106-
// consider these types as Codable if the nested type is not Codable.
107-
// Look through the generic type parameters of these types recursively
108-
// to avoid synthesizing code that will crash at runtime.
109-
//
110-
// We only want to look through generic params for these types; other
111-
// types may validly conform to Codable even if their generic param
112-
// types do not.
113-
nominalTypeDecl == tc.Context.getOptionalDecl() ||
114-
nominalTypeDecl == tc.Context.getArrayDecl() ||
115-
nominalTypeDecl == tc.Context.getSetDecl() ||
116-
nominalTypeDecl == tc.Context.getDictionaryDecl()) {
101+
if (nominalTypeDecl == tc.Context.getImplicitlyUnwrappedOptionalDecl()) {
117102
for (auto paramType : genericType->getGenericArgs()) {
118103
if (typeConformsToCodable(tc, context, paramType, proto) != Conforms)
119104
return DoesNotConform;

stdlib/public/core/Codable.swift

Lines changed: 31 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,153 +4146,72 @@ public extension RawRepresentable where RawValue == String, Self : Decodable {
41464146
// Optional/Collection Type Conformances
41474147
//===----------------------------------------------------------------------===//
41484148

4149-
@_inlineable // FIXME(sil-serialize-all)
4150-
@_versioned // FIXME(sil-serialize-all)
4151-
internal func assertTypeIsEncodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
4152-
guard T.self is Encodable.Type else {
4153-
if T.self == Encodable.self || T.self == Codable.self {
4154-
preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.")
4155-
} else {
4156-
preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.")
4157-
}
4158-
}
4159-
}
4160-
4161-
@_inlineable // FIXME(sil-serialize-all)
4162-
@_versioned // FIXME(sil-serialize-all)
4163-
internal func assertTypeIsDecodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
4164-
guard T.self is Decodable.Type else {
4165-
if T.self == Decodable.self || T.self == Codable.self {
4166-
preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.")
4167-
} else {
4168-
preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.")
4169-
}
4170-
}
4171-
}
4172-
4173-
// Temporary resolution for SR-5206.
4174-
//
4175-
// The following two extension on Encodable and Decodable are used below to provide static type information where we don't have any yet.
4176-
// The wrapped contents of the below generic types have to expose their Encodable/Decodable conformance via an existential cast/their metatype.
4177-
// Since those are dynamic types without static type guarantees, we cannot call generic methods taking those arguments, e.g.
4178-
//
4179-
// try container.encode((someElement as! Encodable))
4180-
//
4181-
// One way around this is to get elements to encode into `superEncoder`s and decode from `superDecoder`s because those interfaces are available via the existentials/metatypes.
4182-
// However, this direct encoding/decoding never gives containers a chance to intercept and do something custom on types.
4183-
//
4184-
// If we instead expose this custom private functionality of writing to/reading from containers directly, the containers do get this chance.
4185-
4186-
// FIXME: Remove when conditional conformance is available.
4187-
extension Encodable {
4188-
@_inlineable // FIXME(sil-serialize-all)
4189-
@_versioned // FIXME(sil-serialize-all)
4190-
internal func __encode(to container: inout SingleValueEncodingContainer) throws { try container.encode(self) }
4191-
@_inlineable // FIXME(sil-serialize-all)
4192-
@_versioned // FIXME(sil-serialize-all)
4193-
internal func __encode(to container: inout UnkeyedEncodingContainer) throws { try container.encode(self) }
4194-
@_inlineable // FIXME(sil-serialize-all)
4195-
@_versioned // FIXME(sil-serialize-all)
4196-
internal func __encode<Key>(to container: inout KeyedEncodingContainer<Key>, forKey key: Key) throws { try container.encode(self, forKey: key) }
4197-
}
4198-
4199-
// FIXME: Remove when conditional conformance is available.
4200-
extension Decodable {
4201-
// Since we cannot call these __init, we'll give the parameter a '__'.
4202-
@_inlineable // FIXME(sil-serialize-all)
4203-
@_versioned // FIXME(sil-serialize-all)
4204-
internal init(__from container: SingleValueDecodingContainer) throws { self = try container.decode(Self.self) }
4205-
@_inlineable // FIXME(sil-serialize-all)
4206-
@_versioned // FIXME(sil-serialize-all)
4207-
internal init(__from container: inout UnkeyedDecodingContainer) throws { self = try container.decode(Self.self) }
4208-
@_inlineable // FIXME(sil-serialize-all)
4209-
@_versioned // FIXME(sil-serialize-all)
4210-
internal init<Key>(__from container: KeyedDecodingContainer<Key>, forKey key: Key) throws { self = try container.decode(Self.self, forKey: key) }
4211-
}
4212-
4213-
// FIXME: Uncomment when conditional conformance is available.
4214-
extension Optional : Encodable /* where Wrapped : Encodable */ {
4149+
extension Optional : Encodable where Wrapped : Encodable {
42154150
@_inlineable // FIXME(sil-serialize-all)
42164151
public func encode(to encoder: Encoder) throws {
4217-
assertTypeIsEncodable(Wrapped.self, in: type(of: self))
4218-
42194152
var container = encoder.singleValueContainer()
42204153
switch self {
42214154
case .none: try container.encodeNil()
4222-
case .some(let wrapped): try (wrapped as! Encodable).__encode(to: &container)
4155+
case .some(let wrapped): try container.encode(wrapped)
42234156
}
42244157
}
42254158
}
42264159

4227-
extension Optional : Decodable /* where Wrapped : Decodable */ {
4160+
extension Optional : Decodable where Wrapped : Decodable {
42284161
@_inlineable // FIXME(sil-serialize-all)
42294162
public init(from decoder: Decoder) throws {
4230-
// Initialize self here so we can get type(of: self).
4231-
self = .none
4232-
assertTypeIsDecodable(Wrapped.self, in: type(of: self))
4233-
42344163
let container = try decoder.singleValueContainer()
4235-
if !container.decodeNil() {
4236-
let metaType = (Wrapped.self as! Decodable.Type)
4237-
let element = try metaType.init(__from: container)
4238-
self = .some(element as! Wrapped)
4164+
if container.decodeNil() {
4165+
self = .none
4166+
} else {
4167+
let element = try container.decode(Wrapped.self)
4168+
self = .some(element)
42394169
}
42404170
}
42414171
}
42424172

4243-
// FIXME: Uncomment when conditional conformance is available.
4244-
extension Array : Encodable /* where Element : Encodable */ {
4173+
extension Array : Encodable where Element : Encodable {
42454174
@_inlineable // FIXME(sil-serialize-all)
42464175
public func encode(to encoder: Encoder) throws {
4247-
assertTypeIsEncodable(Element.self, in: type(of: self))
4248-
42494176
var container = encoder.unkeyedContainer()
42504177
for element in self {
4251-
try (element as! Encodable).__encode(to: &container)
4178+
try container.encode(element)
42524179
}
42534180
}
42544181
}
42554182

4256-
extension Array : Decodable /* where Element : Decodable */ {
4183+
extension Array : Decodable where Element : Decodable {
42574184
@_inlineable // FIXME(sil-serialize-all)
42584185
public init(from decoder: Decoder) throws {
4259-
// Initialize self here so we can get type(of: self).
42604186
self.init()
4261-
assertTypeIsDecodable(Element.self, in: type(of: self))
42624187

4263-
let metaType = (Element.self as! Decodable.Type)
42644188
var container = try decoder.unkeyedContainer()
42654189
while !container.isAtEnd {
4266-
let element = try metaType.init(__from: &container)
4267-
self.append(element as! Element)
4190+
let element = try container.decode(Element.self)
4191+
self.append(element)
42684192
}
42694193
}
42704194
}
42714195

4272-
extension Set : Encodable /* where Element : Encodable */ {
4196+
extension Set : Encodable where Element : Encodable {
42734197
@_inlineable // FIXME(sil-serialize-all)
42744198
public func encode(to encoder: Encoder) throws {
4275-
assertTypeIsEncodable(Element.self, in: type(of: self))
4276-
42774199
var container = encoder.unkeyedContainer()
42784200
for element in self {
4279-
try (element as! Encodable).__encode(to: &container)
4201+
try container.encode(element)
42804202
}
42814203
}
42824204
}
42834205

4284-
extension Set : Decodable /* where Element : Decodable */ {
4206+
extension Set : Decodable where Element : Decodable {
42854207
@_inlineable // FIXME(sil-serialize-all)
42864208
public init(from decoder: Decoder) throws {
4287-
// Initialize self here so we can get type(of: self).
42884209
self.init()
4289-
assertTypeIsDecodable(Element.self, in: type(of: self))
42904210

4291-
let metaType = (Element.self as! Decodable.Type)
42924211
var container = try decoder.unkeyedContainer()
42934212
while !container.isAtEnd {
4294-
let element = try metaType.init(__from: &container)
4295-
self.insert(element as! Element)
4213+
let element = try container.decode(Element.self)
4214+
self.insert(element)
42964215
}
42974216
}
42984217
}
@@ -4321,57 +4240,49 @@ internal struct _DictionaryCodingKey : CodingKey {
43214240
}
43224241
}
43234242

4324-
extension Dictionary : Encodable /* where Key : Encodable, Value : Encodable */ {
4243+
extension Dictionary : Encodable where Key : Encodable, Value : Encodable {
43254244
@_inlineable // FIXME(sil-serialize-all)
43264245
public func encode(to encoder: Encoder) throws {
4327-
assertTypeIsEncodable(Key.self, in: type(of: self))
4328-
assertTypeIsEncodable(Value.self, in: type(of: self))
4329-
43304246
if Key.self == String.self {
43314247
// Since the keys are already Strings, we can use them as keys directly.
43324248
var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
43334249
for (key, value) in self {
43344250
let codingKey = _DictionaryCodingKey(stringValue: key as! String)!
4335-
try (value as! Encodable).__encode(to: &container, forKey: codingKey)
4251+
try container.encode(value, forKey: codingKey)
43364252
}
43374253
} else if Key.self == Int.self {
43384254
// Since the keys are already Ints, we can use them as keys directly.
43394255
var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
43404256
for (key, value) in self {
43414257
let codingKey = _DictionaryCodingKey(intValue: key as! Int)!
4342-
try (value as! Encodable).__encode(to: &container, forKey: codingKey)
4258+
try container.encode(value, forKey: codingKey)
43434259
}
43444260
} else {
43454261
// Keys are Encodable but not Strings or Ints, so we cannot arbitrarily convert to keys.
43464262
// We can encode as an array of alternating key-value pairs, though.
43474263
var container = encoder.unkeyedContainer()
43484264
for (key, value) in self {
4349-
try (key as! Encodable).__encode(to: &container)
4350-
try (value as! Encodable).__encode(to: &container)
4265+
try container.encode(key)
4266+
try container.encode(value)
43514267
}
43524268
}
43534269
}
43544270
}
43554271

4356-
extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */ {
4272+
extension Dictionary : Decodable where Key : Decodable, Value : Decodable {
43574273
@_inlineable // FIXME(sil-serialize-all)
43584274
public init(from decoder: Decoder) throws {
4359-
// Initialize self here so we can print type(of: self).
43604275
self.init()
4361-
assertTypeIsDecodable(Key.self, in: type(of: self))
4362-
assertTypeIsDecodable(Value.self, in: type(of: self))
43634276

43644277
if Key.self == String.self {
43654278
// The keys are Strings, so we should be able to expect a keyed container.
43664279
let container = try decoder.container(keyedBy: _DictionaryCodingKey.self)
4367-
let valueMetaType = Value.self as! Decodable.Type
43684280
for key in container.allKeys {
4369-
let value = try valueMetaType.init(__from: container, forKey: key)
4370-
self[key.stringValue as! Key] = (value as! Value)
4281+
let value = try container.decode(Value.self, forKey: key)
4282+
self[key.stringValue as! Key] = value
43714283
}
43724284
} else if Key.self == Int.self {
43734285
// The keys are Ints, so we should be able to expect a keyed container.
4374-
let valueMetaType = Value.self as! Decodable.Type
43754286
let container = try decoder.container(keyedBy: _DictionaryCodingKey.self)
43764287
for key in container.allKeys {
43774288
guard key.intValue != nil else {
@@ -4385,8 +4296,8 @@ extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */
43854296
debugDescription: "Expected Int key but found String key instead."))
43864297
}
43874298

4388-
let value = try valueMetaType.init(__from: container, forKey: key)
4389-
self[key.intValue! as! Key] = (value as! Value)
4299+
let value = try container.decode(Value.self, forKey: key)
4300+
self[key.intValue! as! Key] = value
43904301
}
43914302
} else {
43924303
// We should have encoded as an array of alternating key-value pairs.
@@ -4400,18 +4311,16 @@ extension Dictionary : Decodable /* where Key : Decodable, Value : Decodable */
44004311
}
44014312
}
44024313

4403-
let keyMetaType = (Key.self as! Decodable.Type)
4404-
let valueMetaType = (Value.self as! Decodable.Type)
44054314
while !container.isAtEnd {
4406-
let key = try keyMetaType.init(__from: &container)
4315+
let key = try container.decode(Key.self)
44074316

44084317
guard !container.isAtEnd else {
44094318
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath,
44104319
debugDescription: "Unkeyed container reached end before value in key-value pair."))
44114320
}
44124321

4413-
let value = try valueMetaType.init(__from: &container)
4414-
self[key as! Key] = (value as! Value)
4322+
let value = try container.decode(Value.self)
4323+
self[key] = value
44154324
}
44164325
}
44174326
}

test/IDE/complete_generic_optional.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ struct Foo<T> {
1111
// SR-642 Code completion does not instantiate generic arguments of a type wrapped in an optional
1212
let x: Foo<Bar>? = Foo<Bar>()
1313
x.#^FOO_OPTIONAL_1^#
14-
// FOO_OPTIONAL_1: Begin completions, 7 items
14+
// FOO_OPTIONAL_1: Begin completions, 6 items
1515
// FOO_OPTIONAL_1-DAG: Decl[InstanceMethod]/CurrNominal/Erase[1]: ?.myFunction({#(foobar): Bar#})[#Void#]; name=myFunction(foobar: Bar)
1616
// FOO_OPTIONAL_1: End completions

0 commit comments

Comments
 (0)