New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[SR-7410] Cannot use mutating member on immutable value: 'container' is immutable #49953
Comments
Looks like this is just a bad message that's been improved in master:
|
Ah! Note that in Swift 4.0, all Arrays were Decodable, but they would fail at run time if the element type wasn't Decodable. In Swift 4.1 that condition can be expressed at compile time. Your old code never would have worked, though: there's no way to get an Any element out of an archive. |
I'll leave this open for the type checker folks to improve the diagnostic (cc @xedin). Just saying |
Comment by Igor Zarubin (JIRA) @belkadan, I guess better to attach full code. Here I'm trying to decode json dictionary. It worked fine in prev swift version. |
Comment by Igor Zarubin (JIRA) @belkadan, Now it works fine with this extension: extension UnkeyedDecodingContainer {
mutating func decode(_ type: [Any].Type) throws -> [Any] {
var array: [Any] = []
while !isAtEnd {
if let value = try? decode(Bool.self) {
array.append(value)
} else if let value = try? decode(Double.self) {
array.append(value)
} else if let value = try? decode(String.self) {
array.append(value)
} else if let nestedDictionary = try? decode([String: Any].self) {
array.append(nestedDictionary)
} else if let nestedArray = try? decode([Any].self) {
array.append(nestedArray)
} else if try decodeNil() {
continue
}
}
return array
}
mutating func decode(_ type: [String: Any].Type) throws -> [String: Any] {
let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
return try nestedContainer.decode(type)
}
} |
Hm, I'm suspicious that that Dictionary decode works. @itaiferber? |
@belkadan Yeah, the decode call inside of error: no 'decode' candidates produce the expected contextual result type '[String : Any]'
return try nestedContainer.decode(type)
^
note: overloads for 'decode' exist with these result types: Bool, String, Double, Float, Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, T
return try nestedContainer.decode(type)
^ |
izarubinn (JIRA User) Do you have other extensions elsewhere that are allowing this call to compile? |
Comment by Igor Zarubin (JIRA) @itaiferber no |
izarubinn (JIRA User) Hmm, that shouldn't compile, then, or at least not in Swift 4.1 and later. Do you mind please putting together a small self-contained example containing this extension and some code that uses it (a simple Swift file or Playground would be great)? What Xcode build/Swift version are you running? |
Comment by Igor Zarubin (JIRA) |
izarubinn (JIRA User) Sorry for the delay in responding to you. The Playground you attached does have extensions that allow you to decode; specifically, you have extensions on extension KeyedDecodingContainer {
func decode(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any] {
let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
return try container.decode(type)
}
func decodeIfPresent(_ type: [String: Any].Type, forKey key: K) throws -> [String: Any]? {
guard contains(key) else {
return nil
}
return try decode(type, forKey: key)
}
func decode(_ type: [Any].Type, forKey key: K) throws -> [Any] {
var container = try self.nestedUnkeyedContainer(forKey: key)
return try container.decode(type)
}
func decodeIfPresent(_ type: [Any].Type, forKey key: K) throws -> [Any]? {
guard contains(key) else {
return nil
}
return try decode(type, forKey: key)
}
func decode(_ type: [String: Any].Type) throws -> [String: Any] {
var dictionary: [String: Any] = [:]
for key in allKeys {
if let boolValue = try? decode(Bool.self, forKey: key) {
dictionary[key.stringValue] = boolValue
} else if let stringValue = try? decode(String.self, forKey: key) {
dictionary[key.stringValue] = stringValue
} else if let intValue = try? decode(Int.self, forKey: key) {
dictionary[key.stringValue] = intValue
} else if let doubleValue = try? decode(Double.self, forKey: key) {
dictionary[key.stringValue] = doubleValue
} else if let nestedDictionary = try? decode(Dictionary<String, Any>.self, forKey: key) {
dictionary[key.stringValue] = nestedDictionary
} else if let nestedArray = try? decode(Array<Any>.self, forKey: key) {
dictionary[key.stringValue] = nestedArray
}
}
return dictionary
}
} If you write this yourself, then yes, it will compile. |
Comment by Igor Zarubin (JIRA) @itaiferber, yes, I wrote it. I mean it worked in previous swift version just fine with extension for KeyedDecodingContainer. But now i must to use additional extension for UnkeyedDecodingContainer or compiler throws error. |
Attachment: Download
Environment
Swift 4.1
Additional Detail from JIRA
md5: 6f47ea00a03b7f1a5f3e403d62587a2d
Issue Description:
Is this error correct? If yes, how to work around it because function already marked as immutable. It started to reproduce on 4.1 version
From UnkeyedDecodingContainer.swift
Error reproduces in 3 line
Playground is attached
The text was updated successfully, but these errors were encountered: