Skip to content

Conversation

edgarfgp
Copy link
Contributor

Description

Capture multiple block separators: semicolon, comma, offside

/// Represents the location of the separator block and optional position of the semicolon (used for tooling support)
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type BlockSeparator =
    /// A separator consisting of a semicolon ';'
    /// range is the range of the semicolon
    /// position is the position of the semicolon (if available)
    | Semicolon of range: range * position: pos option
    /// A separator consisting of a comma ','
    /// range is the range of the comma
    /// position is the position of the comma (if available)
    | Comma of range: range * position: pos option

    // A separator consisting of a newline
    /// range is the range of the newline
    /// position is the position of the newline (if available)
    | Offside of range: range * position: pos option

    member Range: range

    member Position: pos option

This can be used in multiple places line Record, DU etc. Will also help to have better recovery and error messages.

Split #18881

Checklist

  • Test cases added
  • Release notes entry updated

Copy link
Contributor

github-actions bot commented Sep 12, 2025

❗ Release notes required


✅ Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/10.0.100.md

# Conflicts:
#	tests/FSharp.Compiler.Service.Tests/FSharp.Compiler.Service.SurfaceArea.netstandard20.release.bsl
@edgarfgp edgarfgp marked this pull request as ready for review September 12, 2025 14:43
@edgarfgp edgarfgp requested a review from a team as a code owner September 12, 2025 14:43
@edgarfgp
Copy link
Contributor Author

This is ready :)

@github-project-automation github-project-automation bot moved this from New to In Progress in F# Compiler and Tooling Sep 16, 2025
@T-Gro T-Gro merged commit a276808 into dotnet:main Sep 16, 2025
38 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in F# Compiler and Tooling Sep 16, 2025
Copy link
Member

@auduchinok auduchinok left a comment

Choose a reason for hiding this comment

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

I don't think yet that this is a correct way to model the tree. We should only capture the semicolons and the commas.

Comment on lines +310 to +313
type BlockSeparator =
| Semicolon of range: range * position: pos option
| Comma of range: range * position: pos option
| Offside of range: range * position: pos option
Copy link
Member

@auduchinok auduchinok Sep 18, 2025

Choose a reason for hiding this comment

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

@edgarfgp I don't understand how these types are supposed to work in practice. The separator is wrapped in an option in other places in the tree, e.g. in NamePatPairField. Let's assume the value is Some, i.e. there is a separator. How could it ever be that the position is None in such case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this is fair. I wanted to preserve the shape type BlockSeparator = range * pos option

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me create a PR to make Semicolon position no optional

Comment on lines +369 to +372
// A separator consisting of a newline
/// range is the range of the newline
/// position is the position of the newline (if available)
| Offside of range: range * position: pos option
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to capture this case? And especially the new line? Are there any cases where we rely on it? If yes, let's review them, please. It seems very suspicious. It effectively captures implementation details of how things are parsed and we should not rely on it in any way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we need this to model OBLOCKSEP

seps_block:
  | OBLOCKSEP
     { (rhs parseState 1), None }

Copy link
Member

Choose a reason for hiding this comment

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

Why would we ever want to model it? If that's an implicit separator created by the unrelated subsequent tokens, we should not be relying on it in any way.

Copy link
Member

Choose a reason for hiding this comment

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

And if OBLOCKSEP can be a real token, this info should be carried in it from the LexFilter to the parser, so we could distinguish these cases.

We should not model the tree for non-existent tokens that are generated by subsequent unrelated ones.

@auduchinok
Copy link
Member

The more I think about this change the more I think it should've not been merged as is.

Let's consider using the blockSet.Position property. The previous implementation allowed you to simply check whether a separator exists: it was modeled as an option value. With the current implementation you should never rely on this property, as it can point to a non-existent separator position, breaking the tooling. One should always check all the cases manually to check if there is actually a separator present and then unwrap the separator position manually. Given that the new separator type is used in an option everywhere it makes it very easy to assume that it only contains a value when a real separator is present. It's very easy to break things here without additional workarounds.

edgarfgp added a commit to edgarfgp/fsharp that referenced this pull request Sep 23, 2025
edgarfgp added a commit to edgarfgp/fsharp that referenced this pull request Sep 23, 2025
auduchinok added a commit to JetBrains/fsharp that referenced this pull request Sep 25, 2025
edgarfgp added a commit to edgarfgp/fsharp that referenced this pull request Sep 25, 2025
This reverts commit a276808.

# Conflicts:
#	docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

3 participants