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
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,17 @@ public extension ExpressibleAsSyntaxBuildable {
}
}

public protocol ExpressibleAsTypeBuildable {
public protocol ExpressibleAsTypeBuildable: ExpressibleAsReturnClause {
func createTypeBuildable() -> TypeBuildable
}

public extension ExpressibleAsTypeBuildable {
/// Conformance to `ExpressibleAsReturnClause`.
func createReturnClause() -> ReturnClause {
return ReturnClause(returnType: self)
}
}

public protocol ExpressibleAsCodeBlockItem: ExpressibleAsCodeBlockItemList {
func createCodeBlockItem() -> CodeBlockItem
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
'BinaryOperatorExpr',
'DeclModifier',
'IdentifierExpr'
],
'TypeBuildable': [
'ReturnClause'
]
}

29 changes: 29 additions & 0 deletions Tests/SwiftSyntaxBuilderTest/ProtocolDeclTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import XCTest
import SwiftSyntax
import SwiftSyntaxBuilder

final class ProtocolDeclTests: XCTestCase {
func testProtocolDecl() {
let returnType = ArrayType(elementType: "DeclSyntax")
let input = ParameterClause(parameterListBuilder: {
FunctionParameter(firstName: .identifier("format"), colon: .colon, type: "Format", trailingComma: .comma, attributesBuilder: {})
FunctionParameter(firstName: .identifier("leadingTrivia"), colon: .colon, type: OptionalType(wrappedType: "Trivia"), attributesBuilder: {})
Copy link
Member

Choose a reason for hiding this comment

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

Is the attributesBuilder argument necessary? Shouldn’t it be defaulted?

Copy link
Contributor Author

@kimdv kimdv Feb 8, 2022

Choose a reason for hiding this comment

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

It should yes.
But the problem is that we then get Ambiguous use of 'init'.

I think we should, somehow, solve this as there is many init methods that look like each other so we need to do things like this to avoid the error. It works now, but I think it makes some noice/cluttered code when using it.

This is a long shot, and I'm not sure if it is technically possible, but I'll try to explain.

It would be nice if we could remove this type of init methods, where the convenience init method only have builders as different as the non-convenience init.
Like the one here: https://github.com/apple/swift-syntax/blob/caa735a5a5c41f4fc1769e5c34bb2cde17157400/Sources/SwiftSyntaxBuilder/gyb_generated/BuildableNodes.swift#L5676-L5721

This will mean, in this case, that our AttributeListBuilder need to conform to ExpressibleAsAttributeList.
And then we could things like FunctionParameter(modifiers: { TokenSyntax.public }, firstName: .identifier("format"), colon: .colon, type: "Format", trailingComma: .comma) or
FunctionParameter(modifiers: TokenSyntax.public, firstName: .identifier("format"), colon: .colon, type: "Format", trailingComma: .comma).

I think we before have talked about that the @resultBuilders should conform to some of the protocols.

Copy link
Member

Choose a reason for hiding this comment

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

I see, makes sense 👍 I’m good with merging this as-is.

As to your other question:
If I understand you correctly, you are saying that you’d like to remove the second initializer listed in the code snippet and make AttributeListBuilder conform to ExpressibleAsAttributeList. In that case you expect to be able to use the AttributeListBuilder result builder wherever an ExpressibleAsAttributeList is expected, right?
If this is what you’re suggesting, I’m pretty sure it won’t work. I think the result builder needs to be declared using @AttributeListBuilder on the parameter or otherwise the type checker won’t try to apply it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay! Thanks, than it is this way :)

Did you see my question here too:
#356 (comment)

})
let functionSignature = FunctionSignature(input: input, output: returnType)

// FIXME: We need to add the `modifiersBuilder` with a non-empty value, otherwise will the builder omit newline.
let functionDecl = FunctionDecl(identifier: .identifier("buildDeclList"), signature: functionSignature, modifiersBuilder: { TokenSyntax.public })
let buildable = ProtocolDecl(modifiers: TokenSyntax.public, identifier: .identifier("DeclListBuildable"), members: functionDecl)

let syntax = buildable.buildSyntax(format: Format())

var text = ""
syntax.write(to: &text)

XCTAssertEqual(text, """
public protocol DeclListBuildable{
public func buildDeclList(format: Format, leadingTrivia: Trivia?)-> [DeclSyntax]
}
""")
}
}
1 change: 1 addition & 0 deletions Tests/SwiftSyntaxBuilderTest/ReturnClauseTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ final class ReturnClauseTests: XCTestCase {

let testCases: [UInt: (ExpressibleAsReturnClause, String)] = [
#line: (ReturnClause(returnType: "Int"), "␣-> Int"),
#line: (ArrayType(elementType: "Int"), "␣-> [Int]"),
#line: ("Int", "␣-> Int"),
]

Expand Down