Skip to content

Remove LazyContent and eagerize intermediate token content creation#13054

Draft
Copilot wants to merge 3 commits into
mainfrom
copilot/remove-lazycontent-infrastructure
Draft

Remove LazyContent and eagerize intermediate token content creation#13054
Copilot wants to merge 3 commits into
mainfrom
copilot/remove-lazycontent-infrastructure

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 15, 2026

  • Find latest available version of Microsoft.NET.Sdk.Razor.SourceGenerators.Transport (9.0.0-preview.26159.4 from dotnet8-transport feed)
  • Update VersionOverride in benchmark csproj from 7.0.0-preview.5.22528.1 to 9.0.0-preview.26159.4
  • Verified NuGet resolves the package from dotnet8-transport feed (network download blocked in sandbox)
Original prompt

Summary

Remove the entire LazyContent / lazy IntermediateToken infrastructure. We recently removed a whole bunch of lazy intermediate token usages and the remaining ones add complexity for marginal benefit since almost all token content gets read anyway during code generation.

What to remove/change

1. Delete LazyContent.cs

  • Delete src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/LazyContent.cs

2. Delete LazyContentTests.cs

  • Delete src/Compiler/Microsoft.AspNetCore.Razor.Language/test/Intermediate/LazyContentTests.cs

3. Simplify IntermediateToken.cs

In src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/IntermediateToken.cs:

  • Remove the IsLazy property entirely
  • Change private object _content to private string _content
  • Simplify the Content getter from _content is LazyContent lazy ? lazy.Value : (string)_content to just return _content
  • Remove the private protected IntermediateToken(LazyContent content, SourceSpan? source) constructor

4. Remove LazyContent constructors from token types

  • In CSharpIntermediateToken.cs: Remove the internal CSharpIntermediateToken(LazyContent content, SourceSpan? source) constructor
  • In HtmlIntermediateToken.cs: Remove the internal HtmlIntermediateToken(LazyContent content, SourceSpan? source) constructor

5. Remove generic factory methods from IntermediateNodeFactory.cs

In src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Intermediate/IntermediateNodeFactory.cs:

  • Remove CSharpToken<T>(T arg, Func<T, string> contentFactory, SourceSpan? source = null) method
  • Remove HtmlToken<T>(T arg, Func<T, string> contentFactory, SourceSpan? source = null) method
  • The using System; import can likely be removed too

6. Update all producers to eagerly evaluate content

In DefaultRazorIntermediateNodeLoweringPhase.cs, every call like:

IntermediateNodeFactory.HtmlToken(
    arg: node,
    contentFactory: static node => node.GetContent(),
    source)

should become:

IntermediateNodeFactory.HtmlToken(node.GetContent(), source)

Similarly for CSharp tokens:

IntermediateNodeFactory.CSharpToken(
    arg: node,
    contentFactory: static node => node.GetContent(),
    source: BuildSourceSpanFromNode(node))

should become:

IntermediateNodeFactory.CSharpToken(node.GetContent(), BuildSourceSpanFromNode(node))

There are multiple such call sites in the lowering phase — make sure to update all of them. Key methods to check:

  • VisitMarkupTextLiteral (both in the attribute context and the HTML content context, and the Combine method)
  • VisitMarkupLiteralAttributeValue
  • VisitCSharpExpressionLiteral

Also in VisitMarkupLiteralAttributeValue for the unresolved attribute case, the pattern:

IntermediateNodeFactory.HtmlToken(
    arg: node,
    contentFactory: static node => node.Value?.GetContent() ?? string.Empty,
    source: BuildSourceSpanFromNode(node.Value))

should become:

IntermediateNodeFactory.HtmlToken(node.Value?.GetContent() ?? string.Empty, BuildSourceSpanFromNode(node.Value))

7. Remove IsLazy checks in downstream consumers

In ComponentTypeArgumentIntermediateNode.cs, the GetValue method currently has:

[HtmlContentIntermediateNode { Children: [HtmlIntermediateToken t] }] => t.IsLazy
    ? IntermediateNodeFactory.CSharpToken(
        arg: t,
        contentFactory: static token => token.Content,
        source: t.Source)
    : new CSharpIntermediateToken(t.Content, t.Source),

This should be simplified to just:

[HtmlContentIntermediateNode { Children: [HtmlIntermediateToken t] }] => new CSharpIntermediateToken(t.Content, t.Source),

In DefaultTagHelperResolutionPhase.cs, the ToCSharpToken method:

private static CSharpIntermediateToken ToCSharpToken(HtmlIntermediateToken htmlToken)
{
    return htmlToken.IsLazy
        ? IntermediateNodeFactory.CSharpToken(htmlToken, static t => t.Content, htmlToken.Source)
        : new CSharpIntermediateToken(htmlToken.Content, htmlToken.Source);
}

Should be simplified to:

private static CSharpIntermediateToken ToCSharpToken(HtmlIntermediateToken htmlToken)
{
    return new CSharpIntermediateToken(htmlToken.Content, htmlToken.Source);
}

8. Update test infrastructure

In src/Shared/Microsoft.AspNetCore.Razor.Test.Common/Language/IntegrationTests/IntermediateNodeWriter.cs, the WriteName method has:

else if (node is IntermediateToken token)
{
    _writer.Write(token.IsLazy ? "LazyIntermediateToken" : "IntermediateToken");
}

This should be simplified to:

else if (node is IntermediateToken)
{
    _writer.Write("IntermediateToken");
}

9. Update test baseline files

All .ir.txt test baseline files that contain LazyIntermediateToken need to have those occurrences replaced with IntermediateToken. The ma...

This pull request was created from Copilot chat.

Copilot AI changed the title [WIP] Remove LazyContent and simplify IntermediateToken Remove LazyContent and eagerize intermediate token content creation Apr 15, 2026
Copilot AI requested a review from chsienki April 15, 2026 19:59
…rators.Transport 9.0.0-preview.26159.4

Agent-Logs-Url: https://github.com/dotnet/razor/sessions/91349015-46a0-4857-b955-27c31a157c0a

Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants