Skip to content

Improve diagnostics for effect specifiers #1260

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

Merged
merged 1 commit into from
Jan 26, 2023

Conversation

ahoppen
Copy link
Member

@ahoppen ahoppen commented Jan 24, 2023

Instead of modelling the effect specifiers as keywords in the declaration/signature, create dedicated nodes for them. This greatly simplifies how we can recover from incorrect effect specifiers.

@ahoppen ahoppen requested a review from bnbarham January 24, 2023 19:54
@ahoppen
Copy link
Member Author

ahoppen commented Jan 24, 2023

@swift-ci Please test

Copy link
Contributor

@bnbarham bnbarham left a comment

Choose a reason for hiding this comment

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

Nice 🤩

}

while let misplacedSpecifier = self.consume(ifAnyIn: EffectSpecifier.self) {
if asyncKeyword == nil, S.correctAsyncTokenKinds.contains(misplacedSpecifier.tokenKind) || S.misspelledAsyncTokenKinds.contains(misplacedSpecifier.tokenKind) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This is just AsyncEffectSpecifier right? I think it'd be better to use subsets for all of this, it would be quite a few 😓 . But it doesn't seem great to eg. do the two array concatenations above. Plus if we want to remove the array ifAny anyway...

Copy link
Member Author

Choose a reason for hiding this comment

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

I knew this would come up. I updated it to use RawTokenKindSubset

unexpectedAfterThrows.append(RawSyntax(misplacedSpecifier))
}

if unexpectedBeforeAsync.isEmpty && asyncKeyword == nil && unexpectedBeforeThrows.isEmpty && throwsKeyword == nil && unexpectedAfterThrows.isEmpty {
Copy link
Contributor

Choose a reason for hiding this comment

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

Checking all is fine, but since we always set async/throws we could just check those instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

I’d rather be conservative here to make sure we are not dropping any tokens.

Comment on lines -692 to +687
while let (_, handle) = self.at(anyIn: EffectsSpecifier.self), loopProgress.evaluate(currentToken) {
while let (_, handle) = self.at(anyIn: EffectSpecifier.self), loopProgress.evaluate(currentToken) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We also handle unexpected up to the throws from canRecoverTo. We don't beyond that point though (see other comment).

let _: () 1️⃣throws
}
""",
diagnostics: [
// TODO: Old parser expected error on line 3: consecutive statements on a line must be separated by ';'
// TODO: Old parser expected error on line 3: expected expression
DiagnosticSpec(message: "unexpected 'throws' keyword in function")
Copy link
Contributor

Choose a reason for hiding this comment

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

I assume this is parsed as let _: () // throws ie. a variable with void type?

Copy link
Member Author

Choose a reason for hiding this comment

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

Correct. Added a substructure test

@@ -760,7 +760,7 @@ final class DeclarationTests: XCTestCase {
}
""",
diagnostics: [
DiagnosticSpec(message: "unexpected code 'bogus rethrows set' in variable")
DiagnosticSpec(message: "unexpected code 'bogus' before effect specifiers")
]
)
}
Copy link
Contributor

@bnbarham bnbarham Jan 24, 2023

Choose a reason for hiding this comment

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

func foo() throws bogus {}
func foo() bogus -> Int {}
() bogus reasync -> Int

If I'm reading the code correctly I'm fairly sure they aren't handled well. It'd be good to add + fix these, but also happy to have that in a separate PR if you want though, since it's no worse than what's there at the moment.

Copy link
Member Author

Choose a reason for hiding this comment

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

The first one is handled well. For the other two, I’ll look into them in a follow-up PR.

@ahoppen ahoppen force-pushed the ahoppen/effect-specifiers branch 3 times, most recently from a733687 to 967cbc6 Compare January 25, 2023 08:06
@ahoppen
Copy link
Member Author

ahoppen commented Jan 25, 2023

@swift-ci Please test

@ahoppen
Copy link
Member Author

ahoppen commented Jan 25, 2023

Instead of modelling the effect specifiers as keywords in the declaration/signature, create dedicated nodes for them. This greatly simplifies how we can recover from incorrect effect specifiers.
@ahoppen ahoppen force-pushed the ahoppen/effect-specifiers branch from 967cbc6 to 798c660 Compare January 25, 2023 18:45
@ahoppen ahoppen requested a review from DougGregor as a code owner January 25, 2023 18:45
@ahoppen
Copy link
Member Author

ahoppen commented Jan 25, 2023

@ahoppen ahoppen merged commit 82b90a8 into swiftlang:main Jan 26, 2023
@ahoppen ahoppen deleted the ahoppen/effect-specifiers branch January 26, 2023 07:17
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.

2 participants