Skip to content

[labeled break/continue] Keyword highlighting#83201

Draft
CyrusNajmabadi wants to merge 102 commits intodotnet:features/labeled-break-and-continuefrom
CyrusNajmabadi:stack/highlighting
Draft

[labeled break/continue] Keyword highlighting#83201
CyrusNajmabadi wants to merge 102 commits intodotnet:features/labeled-break-and-continuefrom
CyrusNajmabadi:stack/highlighting

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Apr 16, 2026

Cyrus Najmabadi 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.
@dotnet-policy-service dotnet-policy-service Bot added Community The pull request was submitted by a contributor who is not a Microsoft employee. VSCode labels Apr 16, 2026
Cyrus Najmabadi 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.
@dotnet-policy-service dotnet-policy-service Bot added the Needs API Review Needs to be reviewed by the API review council label Apr 16, 2026
@dotnet-policy-service
Copy link
Copy Markdown
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.

Cyrus Najmabadi 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.
Cyrus Najmabadi 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.
@CyrusNajmabadi CyrusNajmabadi changed the title Add keyword highlighting for labeled break/continue [labeled break/continue] Keyword highlighting Apr 26, 2026
Cyrus Najmabadi and others added 17 commits April 29, 2026 12:43
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee. Needs API Review Needs to be reviewed by the API review council VSCode

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants