Skip to content

Fix NullReferenceException in Entity on unlinked placeholder entities - #20274

Open
xperiandri wants to merge 5 commits into
dotnet:mainfrom
xperiandri:fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities
Open

Fix NullReferenceException in Entity on unlinked placeholder entities#20274
xperiandri wants to merge 5 commits into
dotnet:mainfrom
xperiandri:fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities

Conversation

@xperiandri

Copy link
Copy Markdown
Contributor

Summary

Fixes#20269 by making typed-tree remapping and classification resilient to placeholder/unlinked entities created while the file is in a broken mid-edit state. Instead of allowing a single null placeholder to crash the entire IDE classification pipeline, the compiler now treats absent module-type augmentation data as null and skips the remap/guard path safely.

Changes

@github-actions

github-actionsBot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

❗ Release notes required

You can open this PR in browser to add release notes: open in github.dev

@xperiandri,

Caution

No release notes found for the changed paths (see table below).

Please make sure to add an entry with an informative description of the change as well as link to this pull request, issue and language suggestion if applicable. Release notes for this repository are based on Keep A Changelog format.

The following format is recommended for this repository:

`* . (PR #XXXXX)`

See examples in the files, listed in the table below or in th full documentation at https://fsharp.github.io/fsharp-compiler-docs/release-notes/About.html.

If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

Change pathRelease notes pathDescription
`vsintegration/src`docs/release-notes/.VisualStudio/18.vNext.mdNo release notes found or release notes format is not correct

✅ Found changes and release notes in following paths:

Warning

No PR link found in some release notes, please consider adding it.

Change pathRelease notes pathDescription
`src/Compiler`docs/release-notes/.FSharp.Compiler.Service/11.0.100.mdNo current pull request URL (#20274) found, please consider adding it

@xperiandrixperiandri changed the title Fix NRE on unlinked placeholder entities and add release notesFix NullReferenceException in Entity on unlinked placeholder entitiesAug 17, 2026
@github-actionsgithub-actionsBot added the AI-Tooling-Check-Scanned-Clean Tooling check: diff analyzed, no interesting infrastructure files label Aug 17, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@T-Gro this is another fix (I can move to another PR if you want)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

The Trailing Whitespace extension removed all trailing whitespaces.
I hope it is not an issue.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So if you hide whitespaces you will see the real several lines changed

@T-GroT-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for digging into this — resilient partial classification during mid-edit is a real, worthwhile goal, and the guarded remapTyconAug / entity_modul_type remap in TypedTreeOps.Remapping.fs are the right shape. A few blocking items before this can go in:

It doesn't build. Marking entity_modul_type and entity_tycon_tcaug as | null in TypedTree.fsi propagates nullability to consumers that weren't updated, and nullness warnings are errors here (outside Proto). A local -c Release build fails with FS3261 at:

  • TypedTreeOps.Transforms.fs(991)d.entity_modul_type.Value is the same unguarded deref you fixed in Remapping.fs, missed here.
  • TypedTreePickle.fs(2818)p_maybe_lazy p_modul_typ x.entity_modul_type passes a nullable to a non-nullable target.
  • TypedTreePickle.fs(2837–2852) — eight TyconAugmentation | null incompatibilities in the tcaug pickle/unpickle path.

That's why every Build_And_Test_* leg is red. If you make these fields nullable you have to sweep all consumers, including the pickler.

~1360 lines of the TypedTree.fs diff are trailing-whitespace churn — only ~20 lines are real change. This trips CheckCodeFormatting, buries the actual fix, and will conflict with everything. Please revert the whitespace-only edits (and the lone one in lib.fs) so the diff is just the guards.

Scope of the type change. These fields were already effectively null for NewUnlinked() placeholders (Unchecked.defaultof<_>), so | null documents an existing latent invariant — but flipping two core Entity fields to nullable forces null-checks everywhere and is a big hammer for an IDE-resilience fix. Worth considering whether the dangling unlinked entity reaching the classification path is itself the bug to fix, rather than making the field type nullable tree-wide.

NewUnlinked() value changes are unnecessary and risky. Switching the placeholder to entity_logical_name = "<unknown>", entity_tycon_repr = TNoRepr, entity_typars = NotLazy [] changes observable pre-Link state on the metadata-unpickling hot path. IsLinked keys off entity_attribs (still defaultof), so linkage detection survives, but none of this is needed for the NRE fix — suggest reverting to Unchecked.defaultof<_>.

No regression test. The linked issue has a clean repro (break a type decl mid-edit); please encode it so this can't silently come back.

lib.fsWeakMap.TryAdd behind #if NETSTANDARD2_0 is correct and a nice cleanup, but it's unrelated to the NRE — fine to keep, just calling it out.

One more: the issue body references files/functions not in this diff (vsintegration/src/FSharp.Editor/*, NewModified*, FreeVars, a NullRef-TypedTree-Classification-Fix.md). Reconciling the description with the actual change will help reviewers follow along.

@github-project-automationgithub-project-automationBot moved this from New to In Progress in F# Compiler and ToolingAug 17, 2026
@T-GroT-Gro added the AI-reviewed PR reviewed by AI review council label Aug 17, 2026
@T-Gro
T-Gro self-requested a review August 17, 2026 08:41
@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch from d9c55d0 to 026148dCompareAugust 17, 2026 11:26

@T-GroT-Gro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One note on the null-fallback design (complements the root-cause point).

Comment threadsrc/Compiler/TypedTree/TypedTree.fs Outdated
member x.TypeContents = x.entity_tycon_tcaug
member x.TypeContents =
match x.entity_tycon_tcaug with
| null -> TyconAugmentation.Create()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🤖🕵️ On the null branch TypeContents returns a fresh TyconAugmentation.Create() each access, but callers mutate the result in place (tcaug_super <-, tcaug_abstract <-, tcaug_closed <-). If an unlinked placeholder ever reaches such a path, those writes land on a throwaway object and are silently lost — turning a fail-fast NRE into silent typed-tree corruption.

|null-> TyconAugmentation.Create()

ModuleOrNamespaceType (line 884) has the same shape. A shared sentinel, or keeping unlinked entities out of these paths (the root-cause fix), is safer.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

So do you think we must save TyconAugmentation.Create() on empty Entity creation?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Fixed in the latest commit

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Also, should we then initialize these objects on empty entity creation instead of doing that lazily?

@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch 2 times, most recently from a9fc80b to 24f2fc9CompareAugust 19, 2026 22:13
@github-actionsgithub-actionsBot added ⚠️ Affects-Bootstrap Tooling check: PR touches compiler bootstrap chain ⚠️ Affects-Build-Infra Tooling check: PR touches build infrastructure ⚠️ Scope-Review-Needed Tooling check: PR scope exceeds title/description labels Aug 19, 2026
@github-actions

This comment has been minimized.

xperiandri added a commit to xperiandri/fsharp that referenced this pull request Aug 20, 2026
Always return initialized value for `Entity.entity_modul_type` and `Entity.entity_tycon_tcaug`.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@T-Gro without this I still cannot build anything in VS 2026.
I will remove this from this PR. It is here for testing purposes only.
cc @kerams

xperiandri added a commit to xperiandri/fsharp that referenced this pull request Aug 20, 2026
Always return initialized value for `Entity.entity_modul_type` and `Entity.entity_tycon_tcaug`.
@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch from c3d9be5 to 4a4d62eCompareAugust 20, 2026 00:56
@xperiandri
xperiandri requested a review from T-GroAugust 20, 2026 08:46
xperiandri added a commit to xperiandri/fsharp that referenced this pull request Aug 20, 2026
Always return initialized value for `Entity.entity_modul_type` and `Entity.entity_tycon_tcaug`.
@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch from 4a4d62e to ba36e07CompareAugust 20, 2026 08:51
T-Gro added a commit that referenced this pull request Aug 20, 2026
The previous run was SIGKILL'd by the OOM-killer mid-suite
(0 real test failures; 229 tests never ran). Empty commit to re-run
the pipeline. Same exit-137 flake also hit unrelated PRs #20274 and
#20235 at the same time.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
xperiandri added a commit to xperiandri/fsharp that referenced this pull request Aug 20, 2026
Always return initialized value for `Entity.entity_modul_type` and `Entity.entity_tycon_tcaug`.
@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch from ba36e07 to 3f31b99CompareAugust 20, 2026 12:57
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Tooling Safety Check — Affects-Bootstrap, Affects-Build-Infra, Affects-Compiler-Output, Scope-Review-Needed
Affects-Bootstrap: FSharpBuild.Directory.Build.props changes bootstrap fsc path resolution
Affects-Build-Infra: eng/Build.ps1, build.sh, test-determinism.ps1, Directory.Build.props modified
Affects-Compiler-Output: TypedTree, TypedTreePickle, TypedTreeOps changes affect compiled metadata
Scope-Review-Needed: Build infra + compiler internals changes beyond stated NRE fix

Generated by PR Tooling Safety Check · opus46 4.1M ·

@github-actionsgithub-actionsBot added the ⚠️ Affects-Compiler-Output Tooling check: PR touches IL emission or codegen label Aug 20, 2026
* Used safe `ModuleOrNamespaceType` property instead of `entity_modul_type`.
* Used safe `TypeContents` property instead of `entity_tycon_tcaug`.
* Optimized `TextViewEventsHandler` memory usage with `voption`
Always return initialized value for `Entity.entity_modul_type` and `Entity.entity_tycon_tcaug`.
@xperiandri
xperiandriforce-pushed the fix-NullReferenceException-breaks-IDE-syntax-coloring-on-unlinked-placeholder-entities branch from 45d3fb2 to c199150CompareAugust 21, 2026 14:36
@xperiandri

Copy link
Copy Markdown
ContributorAuthor

@T-Gro is my approach correct now?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚠️ Affects-BootstrapTooling check: PR touches compiler bootstrap chain⚠️ Affects-Build-InfraTooling check: PR touches build infrastructure⚠️ Affects-Compiler-OutputTooling check: PR touches IL emission or codegenAI-reviewedPR reviewed by AI review councilAI-Tooling-Check-Scanned-CleanTooling check: diff analyzed, no interesting infrastructure files⚠️ Scope-Review-NeededTooling check: PR scope exceeds title/description

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

NullReferenceException breaks IDE syntax coloring on unlinked placeholder entities (e.g. broken code mid-edit)

2 participants

@xperiandri@T-Gro