Skip to content
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

Closed
swift-ci opened this issue Aug 24, 2016 · 7 comments
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-2471
Radar None
Original Reporter gwk (JIRA User)
Type Bug
Status Closed
Resolution Done
Environment

Xcode 8 beta 6, also tested with 8-23 snapshot.

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, TypeChecker
Assignee None
Priority Medium

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
^~~~~~

@belkadan
Copy link
Contributor

I don't think this ever compiled—you would have had to take the pointer you got from withUnsafePointer and convert to point to just a single CChar. @atrick, what's the shortest correct way to do this?

@atrick
Copy link
Member

atrick commented Aug 24, 2016

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))!
}

@belkadan
Copy link
Contributor

Simply not specifying the type of ptr should also work here.

@atrick
Copy link
Member

atrick commented Aug 25, 2016

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?

@belkadan
Copy link
Contributor

We've been seeing a fair number of these lately: any mismatch in closure arguments and the diagnostics go ridiculous. cc @rudkx

@swift-ci
Copy link
Collaborator Author

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))
      }

@atrick
Copy link
Member

atrick commented Jul 16, 2019

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

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

3 participants