-
Notifications
You must be signed in to change notification settings - Fork 472
Use default implementation of ExpressibleAs protocol #349
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
Use default implementation of ExpressibleAs protocol #349
Conversation
Oh, that was a typo in my comment. I wasn’t suggesting to add a new protocol but meant |
|
OKay, cool! Will dig into it as it makes totally sense to make this type of conformances |
0bf3f40 to
75052e4
Compare
738323e to
2293f0c
Compare
|
Happy holidays @ahoppen 🎄 I'm currently looking into some problems I can't figure out how to solve.
If I add extension ExpressibleAsTypeExpr {
public func createExprBuildable() -> ExprBuildable {
createTypeExpr()
}
}Then I get I hope you understand, otherwise I will try to explain it again 😁 |
|
I hope you also had happy and relaxing holidays. 💫 Could you push the source state in which you are seeing the issue you described? That would make it easier for me to play around with it. |
|
It was very good, thanks! It should be pushed and update to date with the latest state with the error I described. |
|
If I checkout your branch and build it using ./build-script.py --toolchain /Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2021-12-04-a.xctoolchain/usrit builds fine without any error. |
|
That is strange! 🤷♂️ I have just tried I did try to run it verbose and noticed it was not building SwiftSyntaxBuilder. It did only run: Can you verify that? |
|
Indeed, we are only building |
2293f0c to
1339b31
Compare
|
OK, I used this as an excuse to do refactoring on how the Back to your problem: The solution fell out while I was doing the refactoring. The problem was that some types had multiple default conformances, for example Both |
Just to be clear and ensure that I have understood it correctly (after have read in like 100 times): let foo1: ExprBuildable = PoundColumnExpr()
let foo2: ExpressibleAsStringLiteral = PoundColumnExpr()
func buildSyntax(expo: ExprBuildable) -> ExprBuildable {
return expr. createExprBuildable()
}If I have understood it then, |
|
Probably the easiest way to explain it is by an example, so I created a reduce example, inspired by the one you were facing, without any dependencies on // MARK: - SwiftSyntax nodes
protocol Syntax {
var sourceCode: String { get }
}
protocol ExprSyntax: Syntax {}
struct IntLiteralSyntax: ExprSyntax {
let value: Int
var sourceCode: String {
return String(value)
}
}
struct CodeBlockSyntax: ExprSyntax {
let items: [Syntax]
var sourceCode: String {
let itemsSourceCode = items.map(\.sourceCode).joined(separator: "\n")
return "{\(itemsSourceCode)}"
}
}
// MARK: - ExpressibleAsProtocols
protocol ExpressibleAsSyntaxBuildable {
func buildSyntax() -> Syntax
}
protocol ExpressibleAsExprSyntaxBuildable: ExpressibleAsSyntaxBuildable {
func buildExprSyntax() -> ExprSyntax
}
extension ExpressibleAsExprSyntaxBuildable {
func buildSyntax() -> Syntax {
return self.buildExprSyntax()
}
}
/// The problem is this conformance `ExpressibleAsIntLiteral: ExpressibleAsCodeBlock`
protocol ExpressibleAsIntLiteral: ExpressibleAsCodeBlock, ExpressibleAsExprSyntaxBuildable {
func buildIntLiteral() -> IntLiteralSyntax
}
extension ExpressibleAsIntLiteral {
func buildExprSyntax() -> ExprSyntax {
return buildIntLiteral()
}
func buildCodeBlock() -> CodeBlockSyntax {
return CodeBlockSyntax(items: [self.buildIntLiteral()])
}
// This is the solution to the problem, uncomment when reading "Solution" below
// func buildSyntax() -> Syntax {
// return buildIntLiteral()
// }
}
protocol ExpressibleAsCodeBlock: ExpressibleAsSyntaxBuildable {
func buildCodeBlock() -> CodeBlockSyntax
}
extension ExpressibleAsCodeBlock {
func buildSyntax() -> Syntax {
return buildCodeBlock()
}
}
// MARK: - BuildableNodes
struct IntLiteral: ExpressibleAsIntLiteral {
let value: Int
func buildIntLiteral() -> IntLiteralSyntax {
return IntLiteralSyntax(value: value)
}
}
struct CodeBlock: ExpressibleAsCodeBlock {
let items: [IntLiteral]
func buildCodeBlock() -> CodeBlockSyntax {
return CodeBlockSyntax(items: items.map({ $0.buildIntLiteral() }))
}
}
// MARK: - Code that triggers the issue
let x = IntLiteral(value: 42)
print(x.buildSyntax().sourceCode)
/// Which path should the call to `buildSyntax` take?
/// Option 1 with call stack:
/// - `ExpressibleAsExprLiteral.buildSyntax()` (available because `IntLiteral` transitively conforms to `ExpressibleAsExprLiteral` via `ExpressibleAsIntLiteral`)
/// - `ExpressibleAsIntLiteral.buildExprSyntax()`
/// - `IntLiteral.buildIntLiteral()`
/// This option produces the result `42`.
///
/// Option 2 with call stack:
/// - `ExpressibleAsCodeBlock.buildSyntax()` (available because `IntLiteral` transitively conforms to `ExpressibleAsExprLiteral` via `ExpressibleAsIntLiteral`)
/// - `ExporessibleAsIntLiteral.buildCodeBlock()` (effectively wrapping `42` in braces)
/// - `IntLiteral.buildIntLiteral`
/// This option produces the result `{42}`.
///
/// The solution is to add the uncommented code above. In that case the `buildSyntax` methods in `ExpressibleAsExprLiteral` and `ExpressibleAsCodeBlock` are overriden by `ExpressibleAsIntLiteral.buildSyntax`, so there is no ambiguity anymore. |
|
Fixed in #350 |
swiftlang/swift#40436
Comment from swiftlang/swift#40358
I've had something in the works. Found a branch.
The difference is though, that I wanted to add default implementation to
ExpressibleAsSyntaxBuildable,ExpressibleAsStmtBuildableetc.@ahoppen you write
Will you introduce a new protocol for all SYNTAX_BASE_KINDS or is it an type, and do you think of the already generated
ExpressibleAsExprBuildable?