Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/release-notes/.FSharp.Compiler.Service/10.0.100.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
* Parser: Capture named fields block separators. ([PR #18857](https://github.com/dotnet/fsharp/pull/18857))
* Type checker: use inner expr range in upcast constraints errors ([PR #18850](https://github.com/dotnet/fsharp/pull/18850))
* Import `IEnumerable` as `seq`. ([PR #18865](https://github.com/dotnet/fsharp/pull/18865))
* Parser: Capture multiple block separators ([PR #18899](https://github.com/dotnet/fsharp/pull/18899))

### Breaking Changes

Expand Down
19 changes: 12 additions & 7 deletions src/Compiler/Checking/CheckRecordSyntaxHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,19 @@ let TransformAstForNestedUpdates (cenv: TcFileState) (env: TcEnv) overallTy (lid
let totalRange (origId: Ident) (id: Ident) =
withStartEnd origId.idRange.End id.idRange.Start origId.idRange

match withExpr with
| SynExpr.Ident origId, (blockSep: BlockSeparator) ->
let lid, rng = upToId blockSep.Range id (origId :: ids)
let rangeOfBlockSeparator (id: Ident) =
let idEnd = id.idRange.End
let blockSeparatorStartCol = idEnd.Column
let blockSeparatorEndCol = blockSeparatorStartCol + 4
let blockSeparatorStartPos = mkPos idEnd.Line blockSeparatorStartCol
let blockSeparatorEndPos = mkPos idEnd.Line blockSeparatorEndCol

withStartEnd blockSeparatorStartPos blockSeparatorEndPos id.idRange

Some(
SynExpr.LongIdent(false, LongIdentWithDots(lid, rng), None, totalRange origId id),
BlockSeparator.Offside(blockSep.Range, None)
)
match withExpr with
| SynExpr.Ident origId, (sepRange, _) ->
let lid, rng = upToId sepRange id (origId :: ids)
Some(SynExpr.LongIdent(false, LongIdentWithDots(lid, rng), None, totalRange origId id), (rangeOfBlockSeparator id, None))
| _ -> None

let rec synExprRecd copyInfo (outerFieldId: Ident) innerFields exprBeingAssigned =
Expand Down
4 changes: 2 additions & 2 deletions src/Compiler/Checking/CheckRecordSyntaxHelpers.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ open FSharp.Compiler.TypedTree
val GroupUpdatesToNestedFields:
fields: ((Ident list * Ident) * SynExpr option) list -> ((Ident list * Ident) * SynExpr option) list

val TransformAstForNestedUpdates:
val TransformAstForNestedUpdates<'a> :
cenv: TcFileState ->
env: TcEnv ->
overallTy: TType ->
lid: LongIdent ->
exprBeingAssigned: SynExpr ->
withExpr: SynExpr * BlockSeparator ->
withExpr: SynExpr * (range * 'a) ->
(Ident list * Ident) * SynExpr option

val BindOriginalRecdExpr:
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/Expressions/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7763,7 +7763,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m

match withExprOpt, synLongId.LongIdent, exprBeingAssigned with
| _, [ id ], _ -> ([], id), exprBeingAssigned
| Some (origExpr, blockSep), lid, Some exprBeingAssigned -> TransformAstForNestedUpdates cenv env overallTy lid exprBeingAssigned (origExpr, blockSep)
| Some withExpr, lid, Some exprBeingAssigned -> TransformAstForNestedUpdates cenv env overallTy lid exprBeingAssigned withExpr
| _ -> List.frontAndBack synLongId.LongIdent, exprBeingAssigned)

let flds = if hasOrigExpr then GroupUpdatesToNestedFields flds else flds
Expand Down
24 changes: 12 additions & 12 deletions src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,12 @@ module SyntaxTraversal =
| SynExpr.AnonRecd(copyInfo = copyOpt; recordFields = fields) ->
[
match copyOpt with
| Some(expr, blockSep) ->
| Some(expr, (withRange, _)) ->
yield dive expr expr.Range traverseSynExpr

yield
dive () blockSep.Range (fun () ->
if posGeq pos blockSep.Range.End then
dive () withRange (fun () ->
if posGeq pos withRange.End then
// special case: caret is after WITH
// { x with $ }
visitor.VisitRecordField(path, Some expr, None)
Expand Down Expand Up @@ -498,24 +498,24 @@ module SyntaxTraversal =
traverseSynExpr expr)

match sepOpt with
| Some blockSep ->
| Some(sep, scPosOpt) ->
yield
dive () blockSep.Range (fun () ->
dive () sep (fun () ->
// special case: caret is below 'inherit' + one or more fields are already defined
// inherit A()
// $
// field1 = 5
diveIntoSeparator inheritRange.StartColumn blockSep.Position None)
diveIntoSeparator inheritRange.StartColumn scPosOpt None)
| None -> ()
| _ -> ()

match copyOpt with
| Some(expr, blockSep) ->
| Some(expr, (withRange, _)) ->
yield dive expr expr.Range traverseSynExpr

yield
dive () blockSep.Range (fun () ->
if posGeq pos blockSep.Range.End then
dive () withRange (fun () ->
if posGeq pos withRange.End then
// special case: caret is after WITH
// { x with $ }
visitor.VisitRecordField(path, Some expr, None)
Expand Down Expand Up @@ -556,14 +556,14 @@ module SyntaxTraversal =
| None -> ()

match sepOpt with
| Some blockSep ->
| Some(sep, scPosOpt) ->
yield
dive () blockSep.Range (fun () ->
dive () sep (fun () ->
// special case: caret is between field bindings
// field1 = 5
// $
// field2 = 5
diveIntoSeparator offsideColumn blockSep.Position copyOpt)
diveIntoSeparator offsideColumn scPosOpt copyOpt)
| _ -> ()

]
Expand Down
18 changes: 1 addition & 17 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -306,23 +306,7 @@ type DebugPointAtBinding =

type SeqExprOnly = SeqExprOnly of bool

[<NoEquality; NoComparison; RequireQualifiedAccess>]
type BlockSeparator =
| Semicolon of range: range * position: pos option
| Comma of range: range * position: pos option
| Offside of range: range * position: pos option

member this.Range =
match this with
| Semicolon(range = m)
| Comma(range = m)
| Offside(range = m) -> m

member this.Position =
match this with
| Semicolon(position = p)
| Comma(position = p)
| Offside(position = p) -> p
type BlockSeparator = range * pos option

type RecordFieldName = SynLongIdent * bool

Expand Down
23 changes: 3 additions & 20 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -354,26 +354,9 @@ type SeqExprOnly =
/// Indicates if a for loop is 'for x in e1 -> e2', only valid in sequence expressions
| SeqExprOnly of bool

/// 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
/// Represents the location of the separator block + optional position
/// of the semicolon (used for tooling support)
type BlockSeparator = range * pos option

/// Represents a record field name plus a flag indicating if given record field name is syntactically
/// correct and can be used in name resolution.
Expand Down
16 changes: 8 additions & 8 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -5709,7 +5709,7 @@ recdExprCore:
| appExpr
{ let mExpr = rhs parseState 1
reportParseErrorAt mExpr (FSComp.SR.parsFieldBinding ())
Some($1, BlockSeparator.Offside(mExpr.EndRange, None)), [] }
Some($1, (mExpr.EndRange, None)), [] }

/*
handles cases when identifier can start from the underscore
Expand Down Expand Up @@ -5743,15 +5743,15 @@ recdExprCore:
| appExpr WITH recdBinding recdExprBindings opt_seps_block
{ let l = List.rev $4
let l = rebindRanges $3 l $5
(Some($1, BlockSeparator.Offside(rhs parseState 2, None)), l) }
(Some($1, (rhs parseState 2, None)), l) }

| appExpr OWITH opt_seps_block OEND
{ (Some($1, BlockSeparator.Offside(rhs parseState 2, None)), []) }
{ (Some($1, (rhs parseState 2, None)), []) }

| appExpr OWITH recdBinding recdExprBindings opt_seps_block OEND
{ let l = List.rev $4
let l = rebindRanges $3 l $5
(Some($1, BlockSeparator.Offside(rhs parseState 2, None)), l) }
(Some($1, (rhs parseState 2, None)), l) }

opt_seps_block:
| seps_block
Expand All @@ -5762,17 +5762,17 @@ opt_seps_block:

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

| SEMICOLON
{ let m = (rhs parseState 1)
BlockSeparator.Semicolon(m, Some m.End) }
m, Some m.End }

| SEMICOLON OBLOCKSEP
{ BlockSeparator.Semicolon((rhs2 parseState 1 2), Some (rhs parseState 1).End) }
{ (rhs2 parseState 1 2), Some (rhs parseState 1).End }

| OBLOCKSEP SEMICOLON
{ BlockSeparator.Semicolon((rhs2 parseState 1 2), Some (rhs parseState 2).End) }
{ (rhs2 parseState 1 2), Some (rhs parseState 2).End }


/* identifier can start from the underscore */
Expand Down
Loading
Loading