Merge pull request #11315 from itaiferber/fix-sr-5206-hack

Remove previous hack for SR-5206
diff --git a/stdlib/public/SDK/Foundation/Data.swift b/stdlib/public/SDK/Foundation/Data.swift
index a6b0f7b..8b3e54f 100644
--- a/stdlib/public/SDK/Foundation/Data.swift
+++ b/stdlib/public/SDK/Foundation/Data.swift
@@ -1827,27 +1827,11 @@
 
 extension Data : Codable {
     public init(from decoder: Decoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        do {
-            let singleValueContainer = try decoder.singleValueContainer()
-            if let decoder = singleValueContainer as? _JSONDecoder {
-                switch decoder.options.dataDecodingStrategy {
-                case .deferredToData:
-                    break /* fall back to default implementation below; this would recurse */
-
-                default:
-                    // _JSONDecoder has a hook for Datas; this won't recurse since we're not going to defer back to Data in _JSONDecoder.
-                    self = try singleValueContainer.decode(Data.self)
-                    return
-                }
-            }
-        } catch { /* fall back to default implementation below */ }
-
         var container = try decoder.unkeyedContainer()
         
         // It's more efficient to pre-allocate the buffer if we can.
         if let count = container.count {
-            self = Data(count: count)
+            self.init(count: count)
             
             // Loop only until count, not while !container.isAtEnd, in case count is underestimated (this is misbehavior) and we haven't allocated enough space.
             // We don't want to write past the end of what we allocated.
@@ -1856,7 +1840,7 @@
                 self[i] = byte
             }
         } else {
-            self = Data()
+            self.init()
         }
         
         while !container.isAtEnd {
@@ -1866,21 +1850,6 @@
     }
     
     public func encode(to encoder: Encoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        // We are allowed to request this container as long as we don't encode anything through it when we need the unkeyed container below.
-        var singleValueContainer = encoder.singleValueContainer()
-        if let encoder = singleValueContainer as? _JSONEncoder {
-            switch encoder.options.dataEncodingStrategy {
-            case .deferredToData:
-                break /* fall back to default implementation below; this would recurse */
-
-            default:
-                // _JSONEncoder has a hook for Datas; this won't recurse since we're not going to defer back to Data in _JSONEncoder.
-                try singleValueContainer.encode(self)
-                return
-            }
-        }
-
         var container = encoder.unkeyedContainer()
         
         // Since enumerateBytes does not rethrow, we need to catch the error, stow it away, and rethrow if we stopped.
diff --git a/stdlib/public/SDK/Foundation/Date.swift b/stdlib/public/SDK/Foundation/Date.swift
index 05dd9d9..c179f30 100644
--- a/stdlib/public/SDK/Foundation/Date.swift
+++ b/stdlib/public/SDK/Foundation/Date.swift
@@ -287,40 +287,13 @@
 
 extension Date : Codable {
     public init(from decoder: Decoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
         let container = try decoder.singleValueContainer()
-        if let decoder = container as? _JSONDecoder {
-            switch decoder.options.dateDecodingStrategy {
-            case .deferredToDate:
-                break /* fall back to default implementation below; this would recurse */
-
-            default:
-                // _JSONDecoder has a hook for Dates; this won't recurse since we're not going to defer back to Date in _JSONDecoder.
-                self = try container.decode(Date.self)
-                return
-            }
-        }
-
         let timestamp = try container.decode(Double.self)
-        self = Date(timeIntervalSinceReferenceDate: timestamp)
+        self.init(timeIntervalSinceReferenceDate: timestamp)
     }
 
     public func encode(to encoder: Encoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        // We are allowed to request this container as long as we don't encode anything through it when we need the keyed container below.
         var container = encoder.singleValueContainer()
-        if let encoder = container as? _JSONEncoder {
-            switch encoder.options.dateEncodingStrategy {
-            case .deferredToDate:
-                break /* fall back to default implementation below; this would recurse */
-
-            default:
-                // _JSONEncoder has a hook for Dates; this won't recurse since we're not going to defer back to Date in _JSONEncoder.
-                try container.encode(self)
-                return
-            }
-        }
-
         try container.encode(self.timeIntervalSinceReferenceDate)
     }
 }
diff --git a/stdlib/public/SDK/Foundation/Decimal.swift b/stdlib/public/SDK/Foundation/Decimal.swift
index f4a2a61..d2523b1 100644
--- a/stdlib/public/SDK/Foundation/Decimal.swift
+++ b/stdlib/public/SDK/Foundation/Decimal.swift
@@ -478,17 +478,6 @@
     }
 
     public init(from decoder: Decoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        do {
-            // We are allowed to request this container as long as we don't decode anything through it when we need the keyed container below.
-            let singleValueContainer = try decoder.singleValueContainer()
-            if singleValueContainer is _JSONDecoder {
-                // _JSONDecoder has a hook for Decimals; this won't recurse since we're not going to defer to Decimal in _JSONDecoder.
-                self  = try singleValueContainer.decode(Decimal.self)
-                return
-            }
-        } catch { /* Fall back to default implementation below. */ }
-
         let container = try decoder.container(keyedBy: CodingKeys.self)
         let exponent = try container.decode(CInt.self, forKey: .exponent)
         let length = try container.decode(CUnsignedInt.self, forKey: .length)
@@ -516,15 +505,6 @@
     }
 
     public func encode(to encoder: Encoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        // We are allowed to request this container as long as we don't encode anything through it when we need the keyed container below.
-        var singleValueContainer = encoder.singleValueContainer()
-        if singleValueContainer is _JSONEncoder {
-            // _JSONEncoder has a hook for Decimals; this won't recurse since we're not going to defer to Decimal in _JSONEncoder.
-            try singleValueContainer.encode(self)
-            return
-        }
-
         var container = encoder.container(keyedBy: CodingKeys.self)
         try container.encode(_exponent, forKey: .exponent)
         try container.encode(_length, forKey: .length)
diff --git a/stdlib/public/SDK/Foundation/JSONEncoder.swift b/stdlib/public/SDK/Foundation/JSONEncoder.swift
index 04a121b..4393b39 100644
--- a/stdlib/public/SDK/Foundation/JSONEncoder.swift
+++ b/stdlib/public/SDK/Foundation/JSONEncoder.swift
@@ -99,7 +99,7 @@
     open var userInfo: [CodingUserInfoKey : Any] = [:]
 
     /// Options set on the top-level encoder to pass down the encoding hierarchy.
-    internal struct _Options {
+    fileprivate struct _Options {
         let dateEncodingStrategy: DateEncodingStrategy
         let dataEncodingStrategy: DataEncodingStrategy
         let nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy
@@ -155,14 +155,14 @@
 
 // MARK: - _JSONEncoder
 
-internal class _JSONEncoder : Encoder {
+fileprivate class _JSONEncoder : Encoder {
     // MARK: Properties
 
     /// The encoder's storage.
     fileprivate var storage: _JSONEncodingStorage
 
     /// Options set on the top-level encoder.
-    internal let options: JSONEncoder._Options
+    fileprivate let options: JSONEncoder._Options
 
     /// The path to the current point in encoding.
     public var codingPath: [CodingKey]
@@ -827,7 +827,7 @@
     open var userInfo: [CodingUserInfoKey : Any] = [:]
 
     /// Options set on the top-level encoder to pass down the decoding hierarchy.
-    internal struct _Options {
+    fileprivate struct _Options {
         let dateDecodingStrategy: DateDecodingStrategy
         let dataDecodingStrategy: DataDecodingStrategy
         let nonConformingFloatDecodingStrategy: NonConformingFloatDecodingStrategy
@@ -871,14 +871,14 @@
 
 // MARK: - _JSONDecoder
 
-internal class _JSONDecoder : Decoder {
+fileprivate class _JSONDecoder : Decoder {
     // MARK: Properties
 
     /// The decoder's storage.
     fileprivate var storage: _JSONDecodingStorage
 
     /// Options set on the top-level decoder.
-    internal let options: JSONDecoder._Options
+    fileprivate let options: JSONDecoder._Options
 
     /// The path to the current point in encoding.
     fileprivate(set) public var codingPath: [CodingKey]
diff --git a/stdlib/public/SDK/Foundation/URL.swift b/stdlib/public/SDK/Foundation/URL.swift
index 262efa7..3799dba 100644
--- a/stdlib/public/SDK/Foundation/URL.swift
+++ b/stdlib/public/SDK/Foundation/URL.swift
@@ -1214,17 +1214,6 @@
     }
 
     public init(from decoder: Decoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        do {
-            // We are allowed to request this container as long as we don't decode anything through it when we need the keyed container below.
-            let singleValueContainer = try decoder.singleValueContainer()
-            if singleValueContainer is _JSONDecoder {
-                // _JSONDecoder has a hook for URLs; this won't recurse since we're not going to defer back to URL in _JSONDecoder.
-                self = try singleValueContainer.decode(URL.self)
-                return
-            }
-        } catch { /* Fall back to default implementation below. */ }
-
         let container = try decoder.container(keyedBy: CodingKeys.self)
         let relative = try container.decode(String.self, forKey: .relative)
         let base = try container.decodeIfPresent(URL.self, forKey: .base)
@@ -1238,15 +1227,6 @@
     }
 
     public func encode(to encoder: Encoder) throws {
-        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
-        // We are allowed to request this container as long as we don't encode anything through it when we need the keyed container below.
-        var singleValueContainer = encoder.singleValueContainer()
-        if singleValueContainer is _JSONEncoder {
-            // _JSONEncoder has a hook for URLs; this won't recurse since we're not going to defer back to URL in _JSONEncoder.
-            try singleValueContainer.encode(self)
-            return
-        }
-
         var container = encoder.container(keyedBy: CodingKeys.self)
         try container.encode(self.relativeString, forKey: .relative)
         if let base = self.baseURL {
diff --git a/stdlib/public/core/Codable.swift b/stdlib/public/core/Codable.swift
index cc23d9f..7af278a 100644
--- a/stdlib/public/core/Codable.swift
+++ b/stdlib/public/core/Codable.swift
@@ -3987,6 +3987,34 @@
     }
 }
 
+// Temporary resolution for SR-5206.
+// 
+// The following two extension on Encodable and Decodable are used below to provide static type information where we don't have any yet.
+// The wrapped contents of the below generic types have to expose their Encodable/Decodable conformance via an existential cast/their metatype.
+// Since those are dynamic types without static type guarantees, we cannot call generic methods taking those arguments, e.g.
+// 
+//   try container.encode((someElement as! Encodable))
+// 
+// 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.
+// However, this direct encoding/decoding never gives containers a chance to intercept and do something custom on types.
+// 
+// If we instead expose this custom private functionality of writing to/reading from containers directly, the containers do get this chance.
+
+// FIXME: Remove when conditional conformance is available.
+extension Encodable {
+    fileprivate func __encode(to container: inout SingleValueEncodingContainer) throws { try container.encode(self) }
+    fileprivate func __encode(to container: inout UnkeyedEncodingContainer)     throws { try container.encode(self) }
+    fileprivate func __encode<Key>(to container: inout KeyedEncodingContainer<Key>, forKey key: Key) throws { try container.encode(self, forKey: key) }
+}
+
+// FIXME: Remove when conditional conformance is available.
+extension Decodable {
+    // Since we cannot call these __init, we'll give the parameter a '__'.
+    fileprivate init(__from container: SingleValueDecodingContainer)   throws { self = try container.decode(Self.self) }
+    fileprivate init(__from container: inout UnkeyedDecodingContainer) throws { self = try container.decode(Self.self) }
+    fileprivate init<Key>(__from container: KeyedDecodingContainer<Key>, forKey key: Key) throws { self = try container.decode(Self.self, forKey: key) }
+}
+
 // FIXME: Uncomment when conditional conformance is available.
 extension Optional : Encodable /* where Wrapped : Encodable */ {
     public func encode(to encoder: Encoder) throws {
@@ -3995,7 +4023,7 @@
         var container = encoder.singleValueContainer()
         switch self {
         case .none: try container.encodeNil()
-        case .some(let wrapped): try (wrapped as! Encodable).encode(to: encoder)
+        case .some(let wrapped): try (wrapped as! Encodable).__encode(to: &container)
         }
     }
 }
@@ -4009,7 +4037,7 @@
         let container = try decoder.singleValueContainer()
         if !container.decodeNil() {
             let metaType = (Wrapped.self as! Decodable.Type)
-            let element = try metaType.init(from: decoder)
+            let element = try metaType.init(__from: container)
             self = .some(element as! Wrapped)
         }
     }
@@ -4022,10 +4050,7 @@
 
         var container = encoder.unkeyedContainer()
         for element in self {
-            // superEncoder appends an empty element and wraps an Encoder around it.
-            // This is normally appropriate for encoding super, but this is really what we want to do.
-            let subencoder = container.superEncoder()
-            try (element as! Encodable).encode(to: subencoder)
+            try (element as! Encodable).__encode(to: &container)
         }
     }
 }
@@ -4039,10 +4064,7 @@
         let metaType = (Element.self as! Decodable.Type)
         var container = try decoder.unkeyedContainer()
         while !container.isAtEnd {
-            // superDecoder fetches the next element as a container and wraps a Decoder around it.
-            // This is normally appropriate for decoding super, but this is really what we want to do.
-            let subdecoder = try container.superDecoder()
-            let element = try metaType.init(from: subdecoder)
+            let element = try metaType.init(__from: &container)
             self.append(element as! Element)
         }
     }
@@ -4054,10 +4076,7 @@
 
         var container = encoder.unkeyedContainer()
         for element in self {
-            // superEncoder appends an empty element and wraps an Encoder around it.
-            // This is normally appropriate for encoding super, but this is really what we want to do.
-            let subencoder = container.superEncoder()
-            try (element as! Encodable).encode(to: subencoder)
+            try (element as! Encodable).__encode(to: &container)
         }
     }
 }
@@ -4071,10 +4090,7 @@
         let metaType = (Element.self as! Decodable.Type)
         var container = try decoder.unkeyedContainer()
         while !container.isAtEnd {
-            // superDecoder fetches the next element as a container and wraps a Decoder around it.
-            // This is normally appropriate for decoding super, but this is really what we want to do.
-            let subdecoder = try container.superDecoder()
-            let element = try metaType.init(from: subdecoder)
+            let element = try metaType.init(__from: &container)
             self.insert(element as! Element)
         }
     }
@@ -4106,29 +4122,22 @@
             var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
             for (key, value) in self {
                 let codingKey = _DictionaryCodingKey(stringValue: key as! String)!
-                let valueEncoder = container.superEncoder(forKey: codingKey)
-                try (value as! Encodable).encode(to: valueEncoder)
+                try (value as! Encodable).__encode(to: &container, forKey: codingKey)
             }
         } else if Key.self == Int.self {
             // Since the keys are already Ints, we can use them as keys directly.
             var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
             for (key, value) in self {
                 let codingKey = _DictionaryCodingKey(intValue: key as! Int)!
-                let valueEncoder = container.superEncoder(forKey: codingKey)
-                try (value as! Encodable).encode(to: valueEncoder)
+                try (value as! Encodable).__encode(to: &container, forKey: codingKey)
             }
         } else {
             // Keys are Encodable but not Strings or Ints, so we cannot arbitrarily convert to keys.
             // We can encode as an array of alternating key-value pairs, though.
             var container = encoder.unkeyedContainer()
             for (key, value) in self {
-                // superEncoder appends an empty element and wraps an Encoder around it.
-                // This is normally appropriate for encoding super, but this is really what we want to do.
-                let keyEncoder = container.superEncoder()
-                try (key as! Encodable).encode(to: keyEncoder)
-
-                let valueEncoder = container.superEncoder()
-                try (value as! Encodable).encode(to: valueEncoder)
+                try (key as! Encodable).__encode(to: &container)
+                try (value as! Encodable).__encode(to: &container)
             }
         }
     }
@@ -4146,8 +4155,7 @@
             let container = try decoder.container(keyedBy: _DictionaryCodingKey.self)
             let valueMetaType = Value.self as! Decodable.Type
             for key in container.allKeys {
-                let valueDecoder = try container.superDecoder(forKey: key)
-                let value = try valueMetaType.init(from: valueDecoder)
+                let value = try valueMetaType.init(__from: container, forKey: key)
                 self[key.stringValue as! Key] = (value as! Value)
             }
         } else if Key.self == Int.self {
@@ -4166,8 +4174,7 @@
                                                                            debugDescription: "Expected Int key but found String key instead."))
                 }
 
-                let valueDecoder = try container.superDecoder(forKey: key)
-                let value = try valueMetaType.init(from: valueDecoder)
+                let value = try valueMetaType.init(__from: container, forKey: key)
                 self[key.intValue! as! Key] = (value as! Value)
             }
         } else {
@@ -4185,19 +4192,14 @@
             let keyMetaType = (Key.self as! Decodable.Type)
             let valueMetaType = (Value.self as! Decodable.Type)
             while !container.isAtEnd {
-                // superDecoder fetches the next element as a container and wraps a Decoder around it.
-                // This is normally appropriate for decoding super, but this is really what we want to do.
-                let keyDecoder = try container.superDecoder()
-                let key = try keyMetaType.init(from: keyDecoder)
+                let key = try keyMetaType.init(__from: &container)
 
                 guard !container.isAtEnd else {
                     throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath,
                                                                                  debugDescription: "Unkeyed container reached end before value in key-value pair."))
                 }
 
-                let valueDecoder = try container.superDecoder()
-                let value = try valueMetaType.init(from: valueDecoder)
-
+                let value = try valueMetaType.init(__from: &container)
                 self[key as! Key] = (value as! Value)
             }
         }