[labeled break/continue] Keyword highlighting#83201
Draft
CyrusNajmabadi wants to merge 102 commits intodotnet:features/labeled-break-and-continuefrom
Draft
[labeled break/continue] Keyword highlighting#83201CyrusNajmabadi wants to merge 102 commits intodotnet:features/labeled-break-and-continuefrom
CyrusNajmabadi wants to merge 102 commits intodotnet:features/labeled-break-and-continuefrom
Conversation
added 10 commits
April 16, 2026 10:35
Add optional Name (IdentifierNameSyntax) to BreakStatementSyntax and ContinueStatementSyntax. The parser consumes an identifier after break/continue when present, matching the goto pattern. No language version gating at the parse level.
Resolves labels via LookupSymbolsWithFallback with LabelsOnly, validates the target is a containing loop (or switch for break), and wires up to the correct LoopBinder/SwitchBinder break/continue label. Gates the feature on C# 14.
Instead of doing a separate label lookup + syntax inspection, BreakLabel and ContinueLabel are now methods that take an optional label name and walk the binder chain naturally. LoopBinder and SwitchBinder detect their immediately-attached label at construction time. Consolidates three error codes into ERR_NoBreakOrContId.
Add SourceLabelOpt to BoundBreakStatement/BoundContinueStatement so ControlFlowPass can mark the user-declared label as referenced, matching how BoundGotoStatement already works.
Verifies each loop type (while, do/while, for, foreach) and switch with both break and continue at the immediate and nested levels. Execution tests confirm correct runtime behavior via console output. IL comparison tests verify that labeled break/continue targeting the immediate construct produces identical IL to the unlabeled equivalent.
…ontinue Replace SourceLabelOpt (LabelSymbol?) with LabelExpressionOpt (BoundLabel?) on BoundBreakStatement and BoundContinueStatement. This stores the full BoundLabel expression in the bound tree, enabling GetSymbolInfo on the label identifier in "break outer;" to correctly resolve to the label symbol — matching how BoundGotoStatement.LabelExpressionOpt works for "goto L;". Tests cover GetSymbolInfo, GetTypeInfo, GetConversion, GetMemberGroup, GetConstantValue, GetAliasInfo, GetDeclaredSymbol, AnalyzeControlFlow, and AnalyzeDataFlow.
Tests IBranchOperation and GetCorrespondingOperation behavior for labeled break/continue targeting immediate and non-immediate (outer) loops and switches. Verifies correct BranchKind, Target labels, and that GetCorrespondingOperation resolves to the intended loop/switch when skipping intervening constructs.
Extends IsLabelContext to recognize break/continue keywords as label positions, and filters recommended labels in GetSymbolsForLabelContext to only include labels on enclosing loops (for continue) or loops and switches (for break) that contain the current position.
Simplifies break/continue handling in GetTargetPositionIfControlFlow to use IBranchOperation.GetCorrespondingOperation() for both labeled and unlabeled cases, removing the syntax-walking helpers TryFindBreakableConstruct and TryFindContinuableConstruct. F12 on the keyword navigates to the target construct (first token for continue, last token for break). F12 on the label identifier navigates to the label declaration via the existing symbol pipeline.
Extends LoopHighlighter and SwitchStatementHighlighter to support labeled break/continue. When a loop or switch has a label, labeled break/continue statements targeting that label are highlighted even when nested inside inner loops or switches. Unlabeled break/continue behavior is unchanged. Non-labeled loops/switches do not highlight labeled break/continue that target an outer construct.
added 3 commits
April 16, 2026 16:11
Add new syntax members to PublicAPI.Unshipped.txt and provide manual forwarding overloads in BreakStatementSyntax.cs/ContinueStatementSyntax.cs so the old shipped signatures (without the name parameter) continue to compile, avoiding a binary breaking change.
Replace hand-maintained contextual keyword list with generated data so the test automatically covers new contextual keywords.
…ontinue Regenerated Microsoft.CodeAnalysis.CSharp.txt baseline to reflect new public API surface: Name/WithName/Update overloads on BreakStatementSyntax and ContinueStatementSyntax, plus the corresponding SyntaxFactory.BreakStatement/ContinueStatement overloads.
10cd451 to
d09e04c
Compare
Contributor
|
This PR modifies public API files. Please follow the instructions at https://github.com/dotnet/roslyn/blob/main/docs/contributing/API%20Review%20Process.md for ensuring all public APIs are reviewed before merging. |
d09e04c to
7c3f983
Compare
added 4 commits
April 16, 2026 21:38
Update the generated grammar to include the optional identifier_name in break_statement and continue_statement productions.
added 2 commits
April 23, 2026 16:13
The Break_/Continue_AwaitForeach_Labeled and Break_/Continue_AsyncIterator_Labeled tests reference Net 10 assemblies, which can't be loaded for execution on a net472 test host. Use the standard IncludeExpectedOutput helper (as in RefFieldTests/CollectionExpressionTests) to skip the runtime check outside CoreClr while still compile-verifying.
Move the `<bind>` markers to wrap the outer labeled statement in each test and invoke `VerifyOperationTreeAndDiagnosticsForTest<LabeledStatementSyntax>` so the tests snapshot the full IOperation tree (including label IDs for branch targets). The `GetCorrespondingOperation` helper is refactored to locate the labeled break/continue directly, independently of the `<bind>` markers now being used for the tree verifier.
Wrap newly added break/continue binding members in `#nullable enable` blocks within their (large) `#nullable disable` host files so we get null-state analysis on the new code: - Binder_Statements.cs: BindBreak / BindContinue / BindBranchLabelAndCheckTarget - InMethodBinder.cs: GetBreakLabel / GetContinueLabel overrides - SwitchBinder.cs: GetBreakLabel override - ControlFlowPass.cs: VisitBreakStatement / VisitContinueStatement overrides LoopBinderContext.cs is tiny and entirely break/continue-related, so the whole file is converted to nullable enable instead of using local pragmas.
Spell out *why* the bound break/continue statement holds a BoundLabel for the labeled-target identifier: - the SemanticModel finds that BoundLabel by matching its Syntax to the IdentifierNameSyntax queried via GetSymbolInfo, and reads LabelSymbol from it; and - ControlFlowPass marks the LabelSymbol as referenced so the "outer:" declaration is not reported as WRN_UnreferencedLabel. Also drops a stale "via SourceLabelOpt below" reference on the break version.
CapturedParametersFinder (built on IdentifierUsedAsValueFinder) walks
descendants looking for identifiers that reference primary-constructor
parameters as values. The label identifier in `break outer;` /
`continue outer;` is a label reference, not a value reference (just
like the label in `goto`), so it should be filtered out the same way.
Without this filter, a labeled break/continue whose label name matches
a primary-constructor parameter (e.g. `class C(int p1) { ... p1: while
(true) { break p1; } }`) would falsely capture the parameter and emit
a backing field for it.
Also fix a stale comment in MethodCompiler.cs that referred to its
addIdentifiers static local function as a "lambda".
Adds a regression test in LabeledBreakContinueBindingTests verifying
that labeled break/continue against a label sharing the parameter's
name leaves the parameter reported as WRN_UnreadPrimaryConstructorParameter.
…mment Move GotoStatementSyntax, BreakStatementSyntax, and ContinueStatementSyntax into their own case section in both childrenNeedChecking (IdentifierUsedAsValueFinder) and addIdentifiers (MethodCompiler), with a comment that explains why we skip them: their identifier children, if any, name labels rather than values. Also drop the `Name: not null` guard from the break/continue cases. An unlabeled break/continue has no identifier children to walk, so always returning false here is equivalent and lets the case better express the shared "this statement names a label" intent.
The inline `// (line,col): error CSXXXX: ...` comments for
ERR_NoBreakOrContId diagnostics referenced stale CS numbers (CS0159,
CS9380) and stale message wordings. ERR_NoBreakOrContId is CS9379 and
its current resource string is "No enclosing loop or switch statement
with the label '{0}' out of which to break or continue". Updated all
23 comments accordingly.
BindBreak and BindContinue are now expression-bodied one-liners that delegate everything (label-name extraction, target lookup, feature availability check, error reporting, label binding, and result construction) to a generic BindBreakOrContinue<TNode> helper. The helper takes two static lambdas: one to look up the matching label target (GetBreakLabel vs GetContinueLabel) and one to construct the success-case bound statement.
Co-authored-by: Julien Couvreur <12466233+jcouv@users.noreply.github.com>
Co-authored-by: Julien Couvreur <12466233+jcouv@users.noreply.github.com>
Co-authored-by: Julien Couvreur <12466233+jcouv@users.noreply.github.com>
This was referenced Apr 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Championed issue: dotnet/csharplang#9875
Speclet: https://github.com/dotnet/csharplang/blob/main/proposals/labeled-break-continue.md#detailed-design
Test plan: #83209
Summary
LoopHighlighterandSwitchStatementHighlighterto propagate label context through recursion.Stacked: