SE-0451 vs `renamed`-attributes

SE-0451 has introduced "raw identifiers", which I believe is very convenient.
While I was thinking that some legacy identifiers should be renamed to raw identifiers, I noticed there were some obstacles(?) when trying to add @available-attributes:

public enum MyNumber {
  case newNumber

  @available(*, deprecated, renamed: "newNumber") // ✅
  public static let oldNumber: MyNumber = .newNumber

  case `123`

  @available(*, deprecated, renamed: "123") // ❌
  // `- error: 'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name
  public static let a123: MyNumber = .`123`

  @available(*, deprecated, renamed: "`123`") // ❌
  // `- error: 'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name
  public static let b123: MyNumber = .`123`

  @available(*, deprecated, renamed: "MyNumber.123") // ❌
  // `- error: 'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name
  public static let c123: MyNumber = .`123`

  @available(*, deprecated, renamed: "MyNumber.`123`") // ❌
  // `- error: 'renamed' argument of 'available' attribute must be an operator, identifier, or full function name, optionally prefixed by a type name
  public static let d123: MyNumber = .`123`

  @available(*, deprecated, message: "'e123' is deprecated: renamed to '123'; use '123' instead.") // ✅ but, auto-fix isn't available...
  public static let e123: MyNumber = .`123`
}

The last one could be a workaround, but it's just a message which doesn't necessarily mean renamed.
Are there any other appropriate ways to warn about deprecation in such situation?

4 Likes

On the other hand, @_dynamicReplacement works without any issues:

// Library
dynamic public func `0123456789`() -> Int? { nil }

// Other Module
@_dynamicReplacement(for: `0123456789`()) // ✅ OK
public func `0123456789_impl`() -> Int? { 1 }

I believe that's because @_dynamicReplacement takes an identifier itself, not a string literal.
I wonder why @available takes a string literal for renamed:.

cc: @allevato

1 Like

Thanks for reporting this!

I don't know what the history is behind why renamed: takes a string instead of a plain identifier, but I have a draft PR that should fix this. I want to add some more coverage for other places where decl names aren't just written as regular identifiers though, like swift_name attributes and APINotes.

2 Likes