Skip to content

Fix the library and inline items from the review - #894

Merged
SimonCropp merged 1 commit into
mainfrom
fix-library
Sep 23, 2026
Merged

SimonCropp merged 1 commit into
mainfrom
fix-library

Conversation

@SimonCropp

Copy link
Copy Markdown
Member

This fixes nine of the eleven "Library and inline" items from todo.md. Each item's repro from review-repros now lives in its topic test class. Two items stay open because each needs a design decision: the dotnet test hang when a viewer is launched, and settle-by-member.

Item Fix Tests
MemberLine takes the nearest same-named declaration A declaration whose span holds the hint wins, the outermost where several do; the nearest is the fallback InlinePatcherTests.ASameNamedMemberInTheNextNestedType*, InlinePatcherFsTests.AnFsLocalNamedLikeTheTestDoesNotFloorTheSearchPastTheHint
NextMemberLine compares indentation by character count Columns, with tab stops of four (IndentWidth) InlinePatcherTests.ATabIndentedLocal*, ControlSpaceIndentedLocalLeavesTheSiblingAlone
F#: a layout-shaped regular literal is AlreadyApplied forever The writer wraps layout-shaped fallback content in "\n"…"\n", and the parser applies StripLayout to regular and verbatim values as SnapshotValue does Two new FsCompilerRoundTripTests cases through fsi, InlinePatcherFsTests.FsPatcherDoesNotCallALayoutShapedRegularLiteralAlreadyApplied
F#: escapes F# does not define are rejected StringLiteral.TryScanRegular takes malformedEscapeIsText: F# keeps the backslash, C# still rejects. A trigraph past 255 wraps, as fsi does with FS1252. All checked against fsi FsStringLiteralTests.Parse (the \0, \12 and \e cases moved over from ParseRejects), InlinePatcherFsTests.FsPatcherUpdatesALiteralHoldingAnUnknownEscape
WildcardFileFinder throws under an undefined variable A root that does not exist, or cannot be listed, has no children WildcardFileFinderTests.AnUndefinedVariable*, ResolvingATwoLevelWildcard*
Sync ViewerLaunchGate.Launch deadlocks behind an async one LaunchAsync runs the launch on the pool and awaits without capture while it holds the gate. The CLAUDE.md note on ConfigureAwait is updated to cover it ViewerLaunchGateTests.SyncLaunchBehindAnAsync*
InlineApplier.Apply throws Opening the mutex and the patcher are guarded, and answer Failed InlineApplierTests.AMutexThisProcessCannotOpenFailsTheApplyRatherThanThrowing
Staged file names over 255 characters The test name is cut to fit 255 UTF-8 bytes, and on .NET Framework to fit MAX_PATH as well, which the net48 run showed is the tighter limit there InlineStagingTests.ALongTestNameIsStillPersisted
A non-viewer on 3493 disables the viewer silently A non-empty reply that isn't the protocol marks the port unowned, and a trace once per port names DiffEngine_ViewerPort ViewerClientUnownedTests.ANonViewerOnThePortIsReportedRatherThanTakenForAnOwner

The full solution passes locally in Release: 2,131 passed, 22 skipped.

- MemberLine prefers a declaration whose span holds the hint, the outermost
  where several do, over one that is merely nearer. A same-named test in the
  next nested type, or an F# local named like the test, put the floor past the
  hint.
- NextMemberLine compares indentation as columns, with tab stops of four. A
  tab indented body under a space indented member ended the member at its
  first local.
- F# escapes that are malformed or not F#'s (\d, \0, \12, \e, \x4, \u12) keep
  the backslash as text, as fsi does, rather than making the literal
  unreadable. A trigraph past 255 wraps into the byte range, as fsi does.
- An F# regular literal is read as the snapshot it holds, with the layout
  convention applied as the test library applies it, and layout-shaped content
  that has to be written as a regular literal is wrapped in layout of its own.
  The patcher called such a literal already applied, so it was never updated.
- WildcardFileFinder finds nothing, rather than throwing, under a root that
  does not exist: an undefined Program Files variable threw out of DiffTools'
  static constructor.
- ViewerLaunchGate.LaunchAsync runs the launch on the pool and does not
  capture the caller's context while it holds the gate, so a sync Launch
  behind it on a single threaded context no longer deadlocks.
- InlineApplier answers Failed where opening the mutex or the patcher throws,
  rather than unwinding a viewer's loop.
- Staged file names cut the test name to fit 255 bytes, and on .NET Framework
  the whole path to MAX_PATH. Longer names were silently not staged.
- A reply on the viewer port that is not the protocol marks the port unowned
  and says once which variable moves DiffEngine off it, rather than being
  taken for an owner that silently took nothing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant