Skip to content

Keep a notion of the in keyword inside the Abstract Syntax Tree. #10198

@nojaf

Description

@nojaf

Is your feature request related to a problem? Please describe.
When a user tries to format the following code with Fantomas, we try and preserve the in keyword. (At least we do in SynExpr.LetOrUse)

let a = 4 in
let b = 5 in
a + b

let x =
    let y = 1 in
    let z = 2 in
    y - z

Currently, this is part of "trivia process" and this information cannot be found in the Untyped Abstract Syntax tree.

ParsedInput.ImplFile
  (ParsedImplFileInput
     ("tmp.fsx", true, QualifiedNameOfFile Tmp$fsx, [], [],
      [SynModuleOrNamespace
         ([Tmp], false, AnonModule,
          [SynModuleDecl.Let
             (false,
              [Binding
                 (None, NormalBinding, false, false, [],
                  PreXmlDoc ((1,4), FSharp.Compiler.XmlDoc+XmlDocCollector),
                  SynValData
                    (None, SynValInfo ([], SynArgInfo ([], false, None)), None),
                  SynPat.Named
                    (SynPat.Wild tmp.fsx (1,4--1,5) IsSynthetic=false, a, false,
                     None, tmp.fsx (1,4--1,5) IsSynthetic=false), None,
                  SynExpr.Const
                    (SynConst.Int32 4, tmp.fsx (1,8--1,9) IsSynthetic=false),
                  tmp.fsx (1,4--1,5) IsSynthetic=false,
                  DebugPointAtBinding tmp.fsx (1,0--1,9) IsSynthetic=false)],
              tmp.fsx (1,0--1,9) IsSynthetic=false);
           SynModuleDecl.Let
             (false,
              [Binding
                 (None, NormalBinding, false, false, [],
                  PreXmlDoc ((2,4), FSharp.Compiler.XmlDoc+XmlDocCollector),
                  SynValData
                    (None, SynValInfo ([], SynArgInfo ([], false, None)), None),
                  SynPat.Named
                    (SynPat.Wild tmp.fsx (2,4--2,5) IsSynthetic=false, b, false,
                     None, tmp.fsx (2,4--2,5) IsSynthetic=false), None,
                  SynExpr.Const
                    (SynConst.Int32 5, tmp.fsx (2,8--2,9) IsSynthetic=false),
                  tmp.fsx (2,4--2,5) IsSynthetic=false,
                  DebugPointAtBinding tmp.fsx (2,0--2,9) IsSynthetic=false)],
              tmp.fsx (2,0--2,9) IsSynthetic=false);
           SynModuleDecl.DoExpr
             (DebugPointAtBinding tmp.fsx (3,0--3,5) IsSynthetic=false,
              SynExpr.App
                (NonAtomic, false,
                 SynExpr.App
                   (NonAtomic, true, SynExpr.Ident op_Addition, SynExpr.Ident a,
                    tmp.fsx (3,0--3,3) IsSynthetic=false), SynExpr.Ident b,
                 tmp.fsx (3,0--3,5) IsSynthetic=false),
              tmp.fsx (3,0--3,5) IsSynthetic=false);
           SynModuleDecl.Let
             (false,
              [Binding
                 (None, NormalBinding, false, false, [],
                  PreXmlDoc ((5,4), FSharp.Compiler.XmlDoc+XmlDocCollector),
                  SynValData
                    (None, SynValInfo ([], SynArgInfo ([], false, None)), None),
                  SynPat.Named
                    (SynPat.Wild tmp.fsx (5,4--5,5) IsSynthetic=false, x, false,
                     None, tmp.fsx (5,4--5,5) IsSynthetic=false), None,
                  SynExpr.LetOrUse
                    (false, false,
                     [Binding
                        (None, NormalBinding, false, false, [],
                         PreXmlDoc
                           ((6,8), FSharp.Compiler.XmlDoc+XmlDocCollector),
                         SynValData
                           (None, SynValInfo ([], SynArgInfo ([], false, None)),
                            None),
                         SynPat.Named
                           (SynPat.Wild tmp.fsx (6,8--6,9) IsSynthetic=false, y,
                            false, None, tmp.fsx (6,8--6,9) IsSynthetic=false),
                         None,
                         SynExpr.Const
                           (SynConst.Int32 1,
                            tmp.fsx (6,12--6,13) IsSynthetic=false),
                         tmp.fsx (6,8--6,9) IsSynthetic=false,
                         DebugPointAtBinding
                           tmp.fsx (6,4--6,13) IsSynthetic=false)],
                     SynExpr.LetOrUse
                       (false, false,
                        [Binding
                           (None, NormalBinding, false, false, [],
                            PreXmlDoc
                              ((7,8), FSharp.Compiler.XmlDoc+XmlDocCollector),
                            SynValData
                              (None,
                               SynValInfo ([], SynArgInfo ([], false, None)),
                               None),
                            SynPat.Named
                              (SynPat.Wild tmp.fsx (7,8--7,9) IsSynthetic=false,
                               z, false, None,
                               tmp.fsx (7,8--7,9) IsSynthetic=false), None,
                            SynExpr.Const
                              (SynConst.Int32 2,
                               tmp.fsx (7,12--7,13) IsSynthetic=false),
                            tmp.fsx (7,8--7,9) IsSynthetic=false,
                            DebugPointAtBinding
                              tmp.fsx (7,4--7,13) IsSynthetic=false)],
                        SynExpr.App
                          (NonAtomic, false,
                           SynExpr.App
                             (NonAtomic, true, SynExpr.Ident op_Subtraction,
                              SynExpr.Ident y,
                              tmp.fsx (8,4--8,7) IsSynthetic=false),
                           SynExpr.Ident z, tmp.fsx (8,4--8,9) IsSynthetic=false),
                        tmp.fsx (7,4--8,9) IsSynthetic=false),
                     tmp.fsx (6,4--8,9) IsSynthetic=false),
                  tmp.fsx (5,4--5,5) IsSynthetic=false, NoDebugPointAtLetBinding)],
              tmp.fsx (5,0--8,9) IsSynthetic=false)], PreXmlDocEmpty, [], None,
          tmp.fsx (1,0--9,0) IsSynthetic=false)], (true, true)))

Describe the solution you'd like
Could we extend SynBinding or another node to preserve this information?

Describe alternatives you've considered
Our current workaround is detecting the IN token via the Tokenizer.

Additional context
I'd like to give this a shot myself if approved.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions