Fsharp: Long line of union cases, records, module, function names breaks coloring (512 characters, specifically)

Created on 25 Jan 2018  路  9Comments  路  Source: dotnet/fsharp

If a line for a DU is sufficiently long (> 512 characters), coloring is broken in Visual Studio 2017.

Repro steps

type TestDU = | A1 of string | A2 of string | A3 of string | A4 of string | A5 of string | A6 of string | A7 of string | A8 of string | A9 of string | A10 of string | A11 of string | A12 | A13 | A14 | A15 | A16 | A17 | A18 | A19 | A20 | A21 | A22 | A23 | A24 | A25 | A26 | A27 | A28 | A29 | A30 | A31 | A32 | A33 | A34 | A35 | A36 | A37 | A38 | A39 | A40 | A41 | A42 | A43 | A44 | A45 | A46 | A47 | A48 | A49 | A50 | A51 | A52 | A53 | A54 | A55 | A56 | A57 | A58 | A59 | A60 | A61 | A62 | A63 | A64 | A65 | A66 | A67AAAAAAAAAAAAAAAAAAAAAAAA of string
type TestRec = { Naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmeeeeeeeeeeee : string; Name2 : string }
module SomeRidiculouslyLongNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmeeeeeeeeeeee =
    let testFunctionNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmmeeeeeeeeeeee () = ()

Expected behavior

Correct coloring of all keywords, cases and types

Actual behavior

The coloring for A67AAAAAAAAAAAAAAAAAAAAAAAA and string are applied to the beginning of the line. (Basically, char % 512.) So ype TestDU = | A1 of string are the coloring for A67AAAAAAAAAAAAAAAAAAAAAAAA, and of after A2 is the color for string at the end of the DU.

On the record example, the colors that should have been applied to string at the end were applied to several a's in the beginning.

On the module example it doesn't even color anything in after the g, looks like the green being applied is from the end of the line (if you delete some a's you see the color move).

Known workarounds

Break cases into multiple lines <= 512 characters.

Related information

Provide any related information

  • OS: Windows 10 Pro x64
  • Branch: Stable
  • Editing took: Visual Studio 2017 15.4.0
  • Severity: Meh (Visual)
Area-IDE Language Service Severity-Medium bug

Most helpful comment

Fixed in #4476

All 9 comments

Interesting that 512 chars is what throws this off. In our own language service, each symbol just has a range captured from name resolution. I suspect that isn't the issue, otherwise, all kinds of problems would be happening beyond this colorization bug.

@olegtk does 512 chars ring a bell?

It's controlled by LongBufferLineThreshold editor option, but it's default value is actually 32K. I assume you don't override it, do you?

There is no UI fro the LongBufferLineThreshold editor option though as it's not meant to be modified by end users. So unless F# fails to provide classification data on this line it might be an editor bug, please route the bug to the editor in that case, @cartermp.

Will do!

@TIHan if you have any bandwidth to debug this to make sure we get classification info for those lines, then that would be great. Otherwise, I can try to get to it this week.

The problem may be the pos/range types, which encode positions in a 64bit struct with limits.

The solution may have to be to move to 96bits or 128bits for these structs, or a reference type. That may impact compiler performance as they are used everywhere, but we should measure.

Is this the same bug? If you remove one character from the string, the bogus error message disappears.
You need to remove several more for coloring to start working so it might be a different limit?

let a username password = 
    sprintf """aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%s%s""" username password

Error FS0001 This expression was expected to have type
''a -> 'b -> 'c'
but here has type
'string'

@asik I think it's related. That string (with quotes) is 512 characters long, which means it's probably hitting the same limit (though it could be in a different location in code).

Coloring is based on the whole line, so I'd bet you have to remove 12 characters for the colors to be right. (Not at a compiler to test it out at the moment.)

Fixed in #4476

Was this page helpful?
0 / 5 - 0 ratings