Skip to content

[XAML] Fix XIHR DataTemplate emission for multi-set and scoped templates - #36683

Merged
StephaneDelcroix merged 2 commits into
net11.0from
feature/xihr-datatemplate-fix
Jul 22, 2026
Merged

[XAML] Fix XIHR DataTemplate emission for multi-set and scoped templates#36683
StephaneDelcroix merged 2 commits into
net11.0from
feature/xihr-datatemplate-fix

Conversation

@StephaneDelcroix

Copy link
Copy Markdown
Contributor

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Hardens the XAML Incremental Hot Reload (XIHR, #34338) DataTemplate source-gen so it produces valid code across real-world XAML. This is a prerequisite for enabling XIHR by default (#36682) — with XIHR on, several repo projects (Essentials.AI.Sample, Controls.TestCases.HostApp, Controls.Xaml.UnitTests) currently fail to build.

XIHR emits a DataTemplate's content as a stably-named LoadTemplate_{line}_{pos} local function so Edit-and-Continue has a stable anchor (#36482). That function was hoisted to the top of the generated method via AddLocalMethod, which breaks in two ways once XIHR is actually enabled:

  • Duplicate method (CS0128 / CS8321). A template value set more than once in the same scope — e.g. a required DataTemplate property, which the generator sets both in the object initializer and as an assignment — emitted the named function twiceerror CS0128: 'LoadTemplate_L_P' is already defined (+ CS8321 unused).
  • Out-of-scope references (CS0103 / CS1503). Hoisting to the method top lost the lambda's lexical scope, so a template body that referenced enclosing locals (the DataTemplate variable, name scopes, resources) generated references to names that don't exist at that scope → CS0103, with a cascading CS1503.

These stayed latent because MAUI ships XIHR opt-in (default off), so no repo project built through this path until default-on was attempted.

Fix

Emit the named local function inline at the point of use (not hoisted), which restores the exact lexical scope the anonymous lambda had, and reserve each method name once per compilation unit so it is declared a single time — every set-site just re-points LoadTemplate at that one function. Also removes ~25 lines of buffering. Non-HR builds are unchanged (still an anonymous lambda).

Tests

Related

XAML Incremental Hot Reload (XIHR, #34338) emits a DataTemplate's content
as a stably-named LoadTemplate_{line}_{pos} local function so Edit-and-
Continue has a stable anchor (#36482). It hoisted that function to the top
of the generated method via AddLocalMethod, which broke in two ways once
XIHR is actually enabled across real-world XAML:

- A template value set more than once in the same scope (e.g. a `required`
  DataTemplate property, set in the object initializer AND as an
  assignment) emitted the named function twice -> CS0128 "already defined"
  + CS8321 "declared but never used".
- Hoisting to the method top lost the lambda's lexical scope, so a template
  body that referenced enclosing locals (the DataTemplate variable, name
  scopes, resources) produced out-of-scope references -> CS0103/CS1503.

These stayed latent because MAUI ships XIHR opt-in (default off), so no
repo project built through this path.

Fix: emit the named local function INLINE at the point of use (restoring
the exact lexical scope the anonymous lambda had) and reserve each method
name once per compilation unit so it is declared a single time, with every
set-site re-pointing LoadTemplate at it.

Adds a regression test covering a `required` DataTemplate property under
XIHR (fails with CS0128 without the fix).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 20, 2026 16:38
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 36683

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 36683"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the XAML Incremental Hot Reload (XIHR) source generator’s DataTemplate emission so the generated C# remains valid when templates are set multiple times and when template bodies depend on the surrounding lexical scope. This unblocks enabling XIHR by default by preventing duplicate local-function declarations and scope-related compilation errors in real-world XAML.

Changes:

  • Emit DataTemplate named LoadTemplate_{line}_{pos} local functions inline at the point of use (instead of hoisting), preserving lexical scope for captured locals.
  • Add per-generation deduplication (TryReserveTemplateMethod) so the named LoadTemplate local function is declared once even if the template is assigned multiple times in the same generated method.
  • Add a regression test covering the “required DataTemplate property set twice” scenario and reformat a couple of test blocks for readability.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/Controls/tests/SourceGen.UnitTests/XamlIncrementalHotReloadPipelineTests.cs Adds a regression test ensuring a multiply-assigned DataTemplate emits a single named LoadTemplate_* method and still compiles under XIHR.
src/Controls/src/SourceGen/Visitors/SetPropertiesVisitor.cs Switches XIHR template generation to inline local-function emission and uses a reservation mechanism to avoid duplicate declarations.
src/Controls/src/SourceGen/SourceGenContext.cs Introduces TryReserveTemplateMethod backed by a root-context HashSet to dedupe emitted template method names.

…er XIHR

Follow-up to the review of #36683. DataTemplate LoadTemplate inline
emission is now deferred out of the required-property (and x:Array)
value-precompute prepass to the main SetPropertiesVisitor pass under
Incremental Hot Reload.

The prepass runs before namescope registration, so a `required`
DataTemplate property whose body used {x:Reference} or a binding to an
outer element emitted a runtime-resolved (XamlServiceProvider) body, and
first-wins dedup kept that instead of the main pass's compile-time
optimized body. Deferring to the main pass (which runs after namescopes
are registered) restores compile-time resolution and drops the redundant
second LoadTemplate assignment. Non-HR builds are unchanged (the deferral
is gated on EnableIncrementalHotReload).

Adds a regression test asserting the required-template x:Reference
resolves to __root at compile time (no SimpleValueTargetProvider), and
updates the multi-set test for the single-assignment result.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 09:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

{
//we might want to move this to a separate method
var visitor = new SetPropertiesVisitor(Context);
var visitor = new SetPropertiesVisitor(Context, valuePrecomputePass: true);
@StephaneDelcroix
StephaneDelcroix merged commit 354686c into net11.0 Jul 22, 2026
32 checks passed
@StephaneDelcroix
StephaneDelcroix deleted the feature/xihr-datatemplate-fix branch July 22, 2026 11:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-xaml XAML, CSS, Triggers, Behaviors

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants