Skip to content

Produce more useful diagnostics for bogus specifier before arrow and leftbrace #1381

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

Conversation

StevenWong12
Copy link
Contributor

Purpose

To produce more useful diagnostics for bogus specifier before arrow and leftbrace as the first step to solve issue #1262

Implementation details

Replace at with recovery function and a new testcase.

Additionally, to pass the testMacroDecl testcase, I made an edit about TokenPrecedence to get the correct precedence of the macro keyword.

I also modified some of the other testcases but I am not sure if they're reasonable.

If there is anything I can do for this PR, please tell me. Many thanks!

@StevenWong12 StevenWong12 requested a review from ahoppen as a code owner March 2, 2023 11:54
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.

Thank you for your contribution @StevenWong12. Your changes look good to me, I've got a few small comments to make sure we don't accidentally parse valid code as invalid with the new recovery.

@StevenWong12
Copy link
Contributor Author

StevenWong12 commented Mar 3, 2023

Thanks for your detailed suggestions! @ahoppen Although the code snippet above was correctly parsed, I think it is indeed a little risky to recover to a left brace on an arbitrary line so I will make changes as your suggestions about checking -> and {.

As for the modification about init function of TokenPrecedence, my original intention was to solve the problems when parsing codes containing multi-line macro declaration with function like signatures e.g.

macro m2(_: Int) = A.M2
macro m3(a b: Int) -> Int = A.M3

Since the marco signature parsing method reuses the logic of function signature parsing, the tokens from = to ) in the second line will be recovered to -> . Specifically, the second macro cannot be recognized as a keyword because it is considered contextual and will be initialized with exprKeyword precedence.

About this issue, I came up with two solutions:

  1. Reduce the recovery precedence of -> to weakPunctuator or exprKeyword inside function signature parsing;
  2. Add a case for RawTokenKind to specify this kind of "contextual keyword" and assign to them when initializing lexeme.

Solution 1 is pretty straightforward but, from my perspective, not pretty fit the context, since the precedence of macro is supposed to be declKeyword
Solution 2 may bring extra wordload but we can explicitly assign a token precedence to these " contextual keywords" in TokenPrecedence.swift

For now, I simply implement solution 1. But it seems solution 2 is a more generic solution, maybe I can implement it in the future if needed. Also, if there is anything I missed or misunderstood, please let me know.

Thanks in advance!

@StevenWong12 StevenWong12 force-pushed the diagnostics-for-bogus-specifier-before-arrow-and-leftbrace branch from 14b0bfa to f5675f5 Compare March 3, 2023 08:54
@StevenWong12 StevenWong12 requested a review from ahoppen March 7, 2023 07:26
@ahoppen
Copy link
Member

ahoppen commented Mar 7, 2023

I just debugged this myself and the problem seems to be that canRecoveryTo is not respecting allowAtStartOfLine when skipping over tokens. The following changes should fix that an remove the need to change the recovery precedence of the arrow. I think one other test case needs to be updated but that’s fine.

diff --git a/Sources/SwiftParser/Declarations.swift b/Sources/SwiftParser/Declarations.swift
index b3368e3c..0d56ef09 100644
--- a/Sources/SwiftParser/Declarations.swift
+++ b/Sources/SwiftParser/Declarations.swift
@@ -1376,7 +1376,7 @@ extension Parser {
 
     let output: RawReturnClauseSyntax?
 
-    if self.at(.arrow) || self.canRecoverTo(TokenSpec(.arrow, recoveryPrecedence: .weakPunctuator, allowAtStartOfLine: false)) != nil {
+    if self.at(.arrow) || self.canRecoverTo(TokenSpec(.arrow, allowAtStartOfLine: false)) != nil {
       output = self.parseFunctionReturnClause(effectSpecifiers: &effectSpecifiers, allowNamedOpaqueResultType: true)
     } else {
       output = nil
diff --git a/Sources/SwiftParser/Recovery.swift b/Sources/SwiftParser/Recovery.swift
index 21b4f7f7..4e48f45d 100644
--- a/Sources/SwiftParser/Recovery.swift
+++ b/Sources/SwiftParser/Recovery.swift
@@ -70,9 +70,10 @@ extension Parser.Lookahead {
     let initialTokensConsumed = self.tokensConsumed
 
     let recoveryPrecedence = min(spec1.recoveryPrecedence, spec2.recoveryPrecedence, spec3.recoveryPrecedence)
+    let shouldSkipOverNewlines = recoveryPrecedence.shouldSkipOverNewlines && spec1.allowAtStartOfLine && spec2.allowAtStartOfLine && spec3.allowAtStartOfLine
 
     while !self.at(.eof) {
-      if !recoveryPrecedence.shouldSkipOverNewlines, self.currentToken.isAtStartOfLine {
+      if !shouldSkipOverNewlines, self.currentToken.isAtStartOfLine {
         break
       }
       let matchedSpec: TokenSpec?

@StevenWong12 StevenWong12 force-pushed the diagnostics-for-bogus-specifier-before-arrow-and-leftbrace branch from f5675f5 to 396ca71 Compare March 8, 2023 02:42
@StevenWong12
Copy link
Contributor Author

Cool! Thanks for your help @ahoppen ! The changes have been committed.😀

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.

Thank you for your contribution @StevenWong12!

@ahoppen
Copy link
Member

ahoppen commented Mar 8, 2023

@swift-ci Please test

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