Improve error messages for keywords used as identifiers in LINQ let clauses#80695
Improve error messages for keywords used as identifiers in LINQ let clauses#80695CyrusNajmabadi merged 14 commits intomainfrom
Conversation
Modified ParseLetClause to detect keywords followed by '=' and use EatTokenEvenWithIncorrectKind to produce ERR_IdentifierExpectedKW error instead of ERR_IdentifierExpected, reducing cascading errors. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Improved code readability by extracting the condition into a well-named helper method as suggested in code review. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| SyntaxToken identifier; | ||
| if (IsReservedKeywordFollowedByEquals()) | ||
| { | ||
| var keyword = this.EatTokenEvenWithIncorrectKind(SyntaxKind.IdentifierToken); | ||
| identifier = ConvertToIdentifier(keyword); | ||
| } | ||
| else | ||
| { | ||
| identifier = this.ParseIdentifierToken(); | ||
| } |
There was a problem hiding this comment.
@copilot conver this to a simple conditional expression. placce the ? and : on new lines with the following expresison on the same line.
There was a problem hiding this comment.
Done in commit 570ed57 - converted to ternary operator with ? and : on new lines.
Address code review feedback by inlining the helper method directly into the if condition in ParseLetClause. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| if (IsReservedKeywordFollowedByEquals()) | ||
| { | ||
| var keyword = this.EatTokenEvenWithIncorrectKind(SyntaxKind.IdentifierToken); | ||
| identifier = ConvertToIdentifier(keyword); |
There was a problem hiding this comment.
@copilot instead of this pair, use EatTokenAsKind instead. We want a missing token here with the keyword attached as a skipped token.
There was a problem hiding this comment.
Done in commit 570ed57 - now using EatTokenAsKind which creates a missing identifier token with the keyword attached as skipped syntax.
- Converted if/else to ternary operator with ? and : on new lines - Changed from EatTokenEvenWithIncorrectKind + ConvertToIdentifier to EatTokenAsKind for better error recovery - Updated test to expect missing identifier token with keyword as skipped syntax Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
| { | ||
| Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.LetKeyword); | ||
| var letKeyword = this.EatContextualToken(SyntaxKind.LetKeyword); | ||
|
|
There was a problem hiding this comment.
@copilot Roslyn disallows blank lines with spaces on them. Please update the copilot contributing document to mention that this should be avoided as it will cause linting errors that will have to be fixed up.
There was a problem hiding this comment.
Done in commit 2ce564d. Fixed the blank lines with spaces in ParseLetClause and updated .github/copilot-instructions.md to include a note about this requirement under the Formatting section.
- Removed spaces from blank lines in ParseLetClause (lines 13908, 13914) - Updated .github/copilot-instructions.md to warn about blank lines with whitespace causing linting errors Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Co-authored-by: Joey Robichaud <jorobich@microsoft.com>
|
@copilot QueryWithMultipleParseErrorsAndScriptParseOption is failing now (since parsing improved in that test case). Can you determine why the test is failing and update the expected results? |
Updated the test to expect the complete query expression 'from i in expr1 let namespace = expr1 select i' instead of the truncated 'from i in expr1 let ' since the parser now recovers better and continues parsing after encountering the keyword. Also removed redundant line from copilot-instructions.md formatting section. Co-authored-by: CyrusNajmabadi <4564579+CyrusNajmabadi@users.noreply.github.com>
Done in commit 9406664. The test was failing because the parser now recovers better - instead of stopping after "let ", it continues parsing to "from i in expr1 let namespace = expr1 select i". Updated the test to expect the complete query expression. |
|
@dotnet/roslyn-compiler this is ready fro review. |
src/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs
Outdated
Show resolved
Hide resolved
|
@dotnet/roslyn-compiler ptal |
| - `dotnet format whitespace --folder . --include <relative path to file>` - Applies formatting preferences to a particular .cs or .vb file | ||
| - When running `dotnet format whitespace` use the `--folder .` option followed by `--include <path to file>` to avoid a design-time build | ||
| - Apply formatting preferences to any modified .cs or .vb file | ||
| - **Important**: Blank lines must not contain any whitespace characters (spaces or tabs). This will cause linting errors that must be fixed. |
There was a problem hiding this comment.
This is 100% going to come back to bite someone when they're trying to test a line of whitespaces, but I don't see any other options.
| [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/11418")] | ||
| public void LetClauseWithKeywordAsIdentifier() | ||
| { | ||
| UsingExpression("from m in methods let params = 1 select m", |
There was a problem hiding this comment.
Can we add one with a contextual keyword, to document behavior?
…or-messages-keyword
Fix error messages for using a keyword instead of an identifier in LINQ let clauses
Issue Summary
When using a reserved keyword (like
params) as an identifier in a LINQletclause, the compiler previously produced many confusing error messages (8-10 errors). The goal was to:Implementation
Modified
LanguageParser.ParseLetClause()to:=(the expected pattern for let clause) using a conditional expressionEatTokenAsKindto create a missing identifier token with the keyword attached as skipped syntaxThis results in just 1 clear error message instead of 8-10 confusing ones.
Changes Made
src/Compilers/CSharp/Portable/Parser/LanguageParser.cs:ParseLetClausemethod using conditional (ternary) expression with?and:on new linesEatTokenAsKindto create missing identifier token with keyword as skipped syntaxsrc/Compilers/CSharp/Test/Syntax/Parsing/ExpressionParsingTests.cs:LetClauseWithKeywordAsIdentifiersrc/Compilers/CSharp/Test/Semantic/Semantics/QueryTests.cs:QueryWithMultipleParseErrorsAndScriptParseOptiontest to expect improved parsing.github/copilot-instructions.md:Test Results
Before/After
Before: Using
paramsin a let clause produced 8+ errors including CS1001, CS1003, CS1525, CS0742, etc.After: Using
paramsin a let clause produces 1 clear CS1041 error: "Identifier expected; 'params' is a keyword"Original prompt
Fixes #11418
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.