Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions Sources/DependenciesMacrosPlugin/DependencyEndpointMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,14 @@ public enum DependencyEndpointMacro: AccessorMacro, PeerMacro {
}
let appliedParameters =
parameters
.enumerated()
.map {
guard let typed = $0.type.as(AttributedTypeSyntax.self),
typed.specifier?.tokenKind == .keyword(.inout)
else { return false }
return true
$1.isInout
? "&p\($0)"
: $1.isAutoclosure
? "p\($0)()"
Copy link
Contributor Author

@xiii111 xiii111 Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only () is OK because @autoclosure can be used only when there are no parameters.
Also inout expression cannot be used on @autoclosure so we don't need to consider the situation when $1.isInout && $1.isAutoclosure.

: "p\($0)"
Comment on lines +167 to +171
Copy link
Contributor Author

@xiii111 xiii111 Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#159 style seemed so cool that I had to try it myself. Originally, I was writing code like this 😅

let appliedParameters =
  parameters
  .enumerated()
  .map {
    if let typed = $1.type.as(AttributedTypeSyntax.self),
       typed.specifier?.tokenKind == .keyword(.inout) {
      return "&p\($0)"
    }
    
    if let typed = $1.type.as(AttributedTypeSyntax.self),
       typed.attributes.contains(where: {
         $0.as(AttributeSyntax.self)?.attributeName.as(IdentifierTypeSyntax.self)?.name.tokenKind == .identifier("autoclosure")
       }) {
      return "p\($0)()"
    }

    return "p\($0)"
  }
  .joined(separator: ", ")

}
.enumerated()
.map { $1 ? "&p\($0)" : "p\($0)" }
.joined(separator: ", ")
decls.append(
"""
Expand Down Expand Up @@ -256,3 +256,26 @@ extension String {
return String(result)
}
}

extension TupleTypeElementSyntax {
fileprivate var isAutoclosure: Bool {
Copy link
Contributor Author

@xiii111 xiii111 Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To obtain this code, I used the Swift AST Explorer. When I input

var bar: (_ a: @autoclosure () -> Int) -> Void

it produced the following output.

スクリーンショット 2023-12-10 19 38 27

self.type
.as(AttributedTypeSyntax.self)?
.attributes
.contains {
$0
.as(AttributeSyntax.self)?
.attributeName
.as(IdentifierTypeSyntax.self)?
.name
.tokenKind == .identifier("autoclosure")
Copy link
Contributor Author

@xiii111 xiii111 Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#159 uses text but I thought tokenKind might be a bit better. Since I'm new to SwiftSyntax, I'll respect your choice.

} ?? false
}

fileprivate var isInout: Bool {
self.type
.as(AttributedTypeSyntax.self)?
.specifier?
.tokenKind == .keyword(.inout)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -796,4 +796,40 @@ final class DependencyEndpointMacroTests: BaseTestCase {
"""
}
}

func testAutoclosure() {
assertMacro {
"""
struct Foo {
@DependencyEndpoint
var bar: (_ a: @autoclosure () -> Int, _ b: () -> Int, _ c: @autoclosure () -> Int) -> Void
Copy link
Contributor Author

@xiii111 xiii111 Dec 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the same naming with #159, like Foo and Bar. The difference from #159 lies in using b as a closure. My intension is to show the difference between closures with and without @autoclosure.

}
"""
} expansion: {
"""
struct Foo {
var bar: (_ a: @autoclosure () -> Int, _ b: () -> Int, _ c: @autoclosure () -> Int) -> Void {
@storageRestrictions(initializes: _bar)
init(initialValue) {
_bar = initialValue
}
get {
_bar
}
set {
_bar = newValue
}
}

func bar(a p0: @autoclosure () -> Int, b p1: () -> Int, c p2: @autoclosure () -> Int) -> Void {
self.bar(p0(), p1, p2())
}

private var _bar: (_ a: @autoclosure () -> Int, _ b: () -> Int, _ c: @autoclosure () -> Int) -> Void = { _, _, _ in
XCTestDynamicOverlay.XCTFail("Unimplemented: 'bar'")
}
}
"""
}
}
}