Skip to content

Conversation

xedin
Copy link
Contributor

@xedin xedin commented Aug 23, 2025

…actor` requirements throwing

The result of both has been made non-optional as well. The idea here is to be able to produce a description for every failure instead of nil result, this is something that package model refactoring actions already do.

The only error we currently have is "not applicable" but that's just a start.

Copy link
Member

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Nice improvement. A couple nitpicks with respect to the new error messages.

/// `nil` is returned.
// TODO: Rather than returning nil, we should consider throwing errors with
// appropriate messages instead.
/// error is thrown.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// error is thrown.
/// an error is thrown.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

return converted?.formatted().as(C.self)
) throws -> C {
guard let converted = call.convertToTrailingClosures(from: context.startAtArgument) else {
throw RefactoringNotApplicableError("")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
throw RefactoringNotApplicableError("")
throw RefactoringNotApplicableError("failed to convert call to trailing closures")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry, I forgot to commit a change to sync this down to convertToTrailingClosures 🤦

return formatted
}

throw RefactoringNotApplicableError("")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
throw RefactoringNotApplicableError("")
throw RefactoringNotApplicableError("failed to format converted expression")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

}

return nil
throw RefactoringNotApplicableError("")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
throw RefactoringNotApplicableError("")
throw RefactoringNotApplicableError("failed to extract initial value of stored variable")

Copy link
Contributor Author

Choose a reason for hiding this comment

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


guard body.count == 1, let item = body.first?.item else {
return nil
throw RefactoringNotApplicableError("getter body is not a single-expression")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
throw RefactoringNotApplicableError("getter body is not a single-expression")
throw RefactoringNotApplicableError("getter body is not a single expression")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

{
guard functionExpression.arguments.isEmpty else { return nil }
guard functionExpression.arguments.isEmpty else {
throw RefactoringNotApplicableError("not a nullary call")
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
throw RefactoringNotApplicableError("not a nullary call")
throw RefactoringNotApplicableError("cannot convert stored property whose initializer is a closure that takes arguments")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

import SwiftSyntax
#endif

public struct RefactoringNotApplicableError: Error, CustomStringConvertible {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public struct RefactoringNotApplicableError: Error, CustomStringConvertible {
/// Error that refactoring actions can throw when the refactoring fails.
///
/// The reason should start with a single character and should be formatted similarly to compiler error messages.
public struct RefactoringNotApplicableError: Error, CustomStringConvertible {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I was thinking whether I should add a comment there or it's self-evident what this is since none other errors declared in swift-syntax do...

Copy link
Contributor

Choose a reason for hiding this comment

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

What does "The reason should start with a single character" mean?

@xedin xedin force-pushed the text-refactor-should-be-able-to-throw branch from a82a2df to ecd3f9d Compare August 23, 2025 06:39
@xedin xedin force-pushed the text-refactor-should-be-able-to-throw branch from ecd3f9d to b6bb15e Compare August 23, 2025 06:45
@xedin
Copy link
Contributor Author

xedin commented Aug 25, 2025

swiftlang/sourcekit-lsp#2251
@swift-ci please test

let converted = try call.convertToTrailingClosures(from: context.startAtArgument)

guard let formatted = converted.formatted().as(C.self) else {
throw RefactoringNotApplicableError("cannot cast formatted call to \(C.self)")
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd prefer keeping them more user-focused. This one is a little weird since it suggests more of an internal failure, maybe just "format error"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

}

return nil
throw RefactoringNotApplicableError("failed to extract initial value of stored variable")
Copy link
Contributor

Choose a reason for hiding this comment

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

The rest are all failures too, how about "could not extract initial value of stored variable"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, I think it should say "property" instead of a "variable" to be consistent with compiler diagnostics.

guard functionExpression.arguments.isEmpty else { return nil }
guard functionExpression.arguments.isEmpty else {
throw RefactoringNotApplicableError(
"cannot convert stored property whose initializer is a closure that takes arguments"
Copy link
Contributor

Choose a reason for hiding this comment

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

Just "initializer is a closure that takes arguments" seems fine? The "cannot convert stored property" is essentially the error itself

import SwiftSyntax
#endif

public struct RefactoringNotApplicableError: Error, CustomStringConvertible {
Copy link
Contributor

Choose a reason for hiding this comment

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

What does "The reason should start with a single character" mean?

Comment on lines 43 to 44
/// - Throws: Throws an error if the refactoring action although applicable
/// fails for some other reason.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this true? Aren't we throwing if it isn't applicable, or did I miss a catch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching this! There were a few places left from the time when Output was still optional in refactor.

return lit
}
public static func refactor(syntax lit: IntegerLiteralExprSyntax, in context: Void) -> IntegerLiteralExprSyntax {
guard lit.literal.text.contains("_") else { return lit }
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this throw with "literal does not contain '_'"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I originally changed it but then reverted, I'd rather fix it in a separate PR.

…actor` requirements throwing

The result of both has been made non-optional as well. The idea
here is to be able to produce a description for every failure
instead of `nil` result, this is something that package model
refactoring actions already do.

The only error we currently have is "not applicable" but that's
just a start.
@xedin xedin force-pushed the text-refactor-should-be-able-to-throw branch from b6bb15e to a379116 Compare August 25, 2025 19:15
@xedin
Copy link
Contributor Author

xedin commented Aug 25, 2025

swiftlang/sourcekit-lsp#2251
@swift-ci please test

@xedin
Copy link
Contributor Author

xedin commented Aug 25, 2025

swiftlang/sourcekit-lsp#2251
@swift-ci please test Windows platform

@xedin xedin merged commit 9c2371a into swiftlang:main Aug 26, 2025
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants