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-2471] Accessing Sized C Array withUnsafePointer() no longer compiles. #45076
Comments
I don't think this ever compiled—you would have had to take the pointer you got from |
This is a common case. I don't yet have a solution for the error message problem. There's almost no way for users to know what they need to write in the signature of their closure! This is the correct, working code: import Foundation
var bytes: (CChar, CChar, CChar, CChar) = (0x61, 0x62, 0x63, 0)
let name: String = withUnsafePointer(to: &bytes) {
(ptr: UnsafePointer<(CChar, CChar, CChar, CChar)>) -> String in
return String(utf8String: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))!
} The migrator (on trunk) will actually insert the "UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self)" for you automatically. The problem is that the migrator can't handle rewriting the closure signature so it never gets to this point. I think a good fix for that would be to give users a useful error message. As far as making the code cleaner, I'd like to move to this idiom in the very near future: import Foundation
var bytes: (CChar, CChar, CChar, CChar) = (0x61, 0x62, 0x63, 0)
let name: String = withUnsafeBytes(of: &bytes) {
return String(utf8String: $0.assumingMemoryBound(to: CChar.self))!
} |
Simply not specifying the type of |
That's right. This works fine in 3.0: import Foundation
var bytes: (CChar, CChar, CChar, CChar) = (0x61, 0x62, 0x63, 0)
let name: String = withUnsafePointer(to: &bytes) { ptr -> String in
return String(utf8String: UnsafeRawPointer(ptr).assumingMemoryBound(to: CChar.self))! In fact, if the 2.2 code were written like this, then the migrator will handle it automatically: import Foundation
var bytes: (CChar, CChar, CChar, CChar) = (0x61, 0x62, 0x63, 0)
let name: String = withUnsafePointer(&bytes) { ptr -> String in
return String(UTF8String: UnsafePointer(ptr))!
} @belkadan This error message is going to cause a lot of grief. Why is it talking about the closure's 'String' return value? And do we already have a bug report for that? |
We've been seeing a fair number of these lately: any mismatch in closure arguments and the diagnostics go ridiculous. cc @rudkx |
Comment by George King (JIRA) Thanks for the guidance, and you are correct about the above not being the actual 2.2 code. My apologies! For the record, what I previously had was: var d_name = entryPtr?.pointee.d_name # tuple of 256 CChar from a dirent struct.
var name = ""
withUnsafePointer(&d_name) {
name = String(cString: UnsafePointer<Int8>($0))
} |
The workarounds above are sufficient for now. This use case will be handled gracefully if we get the following feature: SR-11147: Add withUnsafeBufferPointer(to: variable) where variable is any homogenous aggregate |
Environment
Xcode 8 beta 6, also tested with 8-23 snapshot.
Additional Detail from JIRA
md5: c3a7f37a471f6218b781c8ceb2d0b282
Issue Description:
The following code fails to compile, with an inscrutable error.
Similar code used to compile in earlier betas (probably beta 4), but does not in beta 6 or the 8-23 snapshot.
The intent is to turn a statically sized C array into a String. The real-world use case is for for the BSD dirent struct, which has the field `char d_name[255 + 1];`.
Any guidance on the correct way to do this would be greatly appreciated.
{{
import Foundation
var bytes: (CChar, CChar, CChar, CChar) = (0x61, 0x62, 0x63, 0)
let name: String = withUnsafePointer(to: &bytes) {
(ptr: UnsafePointer<CChar>) -> String in
return String(utf8String: ptr)!
}
}}
test.swift:7:34: error: declared closure result 'String' is incompatible with contextual type '_'
(ptr: UnsafePointer<CChar>) -> String in
^~~~~~
The text was updated successfully, but these errors were encountered: