Skip to content

Commit 82dae72

Browse files
authored
Emit type arguments in correct order (#9621)
* Emit type arguments in correct order * Add baselines
1 parent 642c050 commit 82dae72

File tree

8 files changed

+373
-42
lines changed

8 files changed

+373
-42
lines changed

src/Compiler/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -718,48 +718,8 @@ private void WritePropertyAccess(CodeRenderingContext context, ComponentAttribut
718718

719719
if (componentNode.TypeInferenceNode == null)
720720
{
721-
context.CodeWriter.Write("((global::");
722-
context.CodeWriter.Write(componentNode.Component.GetTypeNamespace());
723-
context.CodeWriter.Write(".");
724-
context.CodeWriter.Write(componentNode.Component.GetTypeNameIdentifier());
725-
if (componentNode.Component.IsGenericTypedComponent())
726-
{
727-
// If there are generic type components, but no type inference node, then it means
728-
// the user specified the type parameters, so we can use them directly
729-
context.CodeWriter.Write("<");
730-
731-
var i = 0;
732-
foreach (var typeArgumentNode in componentNode.Children.OfType<ComponentTypeArgumentIntermediateNode>())
733-
{
734-
if (i++ > 0)
735-
{
736-
context.CodeWriter.Write(", ");
737-
}
738-
739-
writeTypeArgument(typeArgumentNode.Children);
740-
741-
void writeTypeArgument(IntermediateNodeCollection typeArgumentComponents)
742-
{
743-
foreach (var typeArgumentNodeComponent in typeArgumentComponents)
744-
{
745-
switch (typeArgumentNodeComponent)
746-
{
747-
case IntermediateToken { IsCSharp: true } token:
748-
context.CodeWriter.Write(token.Content);
749-
break;
750-
case CSharpExpressionIntermediateNode cSharpExpression:
751-
writeTypeArgument(cSharpExpression.Children);
752-
break;
753-
default:
754-
// As per WriteComponentTypeArgument, we expect every token to be C#, but check just in case
755-
Debug.Fail($"Unexpected non-C# content in a generic type parameter: '{typeArgumentNodeComponent}'");
756-
break;
757-
}
758-
}
759-
}
760-
}
761-
context.CodeWriter.Write(">");
762-
}
721+
context.CodeWriter.Write("((");
722+
TypeNameHelper.WriteGloballyQualifiedName(context.CodeWriter, componentNode.TypeName);
763723
context.CodeWriter.Write(")default)");
764724
}
765725
else

src/Compiler/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7851,6 +7851,44 @@ @using Test
78517851
CompileToAssembly(generated);
78527852
}
78537853

7854+
[IntegrationTestFact, WorkItem("https://github.com/dotnet/razor/issues/9592")]
7855+
public void GenericComponent_TypeParameterOrdering()
7856+
{
7857+
// Arrange
7858+
AdditionalSyntaxTrees.Add(Parse("""
7859+
using Microsoft.AspNetCore.Components;
7860+
7861+
namespace Test;
7862+
7863+
public interface IInterfaceConstraint<T> { }
7864+
7865+
public interface IComposedInterface : IInterfaceConstraint<string> { }
7866+
7867+
public class MyComponent<TService, TKey> : ComponentBase
7868+
where TService : IInterfaceConstraint<TKey>
7869+
{
7870+
[Parameter] public TKey? Value { get; set; }
7871+
[Parameter] public EventCallback<TKey> ValueChanged { get; set; }
7872+
}
7873+
"""));
7874+
7875+
// Act
7876+
var generated = CompileToCSharp("""
7877+
<MyComponent TKey="string" TService="IComposedInterface" @bind-Value="_componentValue" />
7878+
<MyComponent TService="IComposedInterface" TKey="string" @bind-Value="_componentValue" />
7879+
7880+
@code {
7881+
string _componentValue = string.Empty;
7882+
}
7883+
""",
7884+
nullableEnable: true);
7885+
7886+
// Assert
7887+
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
7888+
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
7889+
CompileToAssembly(generated);
7890+
}
7891+
78547892
#endregion
78557893

78567894
#region Key
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using global::System;
7+
using global::System.Collections.Generic;
8+
using global::System.Linq;
9+
using global::System.Threading.Tasks;
10+
using global::Microsoft.AspNetCore.Components;
11+
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
12+
{
13+
#pragma warning disable 219
14+
private void __RazorDirectiveTokenHelpers__() {
15+
}
16+
#pragma warning restore 219
17+
#pragma warning disable 0414
18+
private static object __o = null;
19+
#pragma warning restore 0414
20+
#pragma warning disable 1998
21+
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
22+
{
23+
__o = typeof(
24+
#nullable restore
25+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
26+
string
27+
28+
#line default
29+
#line hidden
30+
#nullable disable
31+
);
32+
__o = typeof(
33+
#nullable restore
34+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
35+
IComposedInterface
36+
37+
#line default
38+
#line hidden
39+
#nullable disable
40+
);
41+
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
42+
#nullable restore
43+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
44+
_componentValue
45+
46+
#line default
47+
#line hidden
48+
#nullable disable
49+
);
50+
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::Microsoft.AspNetCore.Components.EventCallback<string>>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<string>(this,
51+
global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => _componentValue = __value, _componentValue)));
52+
__builder.AddAttribute(-1, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
53+
}
54+
));
55+
#pragma warning disable BL0005
56+
((global::Test.MyComponent<IComposedInterface, string>)default).
57+
#nullable restore
58+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
59+
Value
60+
61+
#line default
62+
#line hidden
63+
#nullable disable
64+
= default;
65+
#pragma warning restore BL0005
66+
#nullable restore
67+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
68+
__o = typeof(global::Test.MyComponent<,>);
69+
70+
#line default
71+
#line hidden
72+
#nullable disable
73+
__o = typeof(
74+
#nullable restore
75+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
76+
IComposedInterface
77+
78+
#line default
79+
#line hidden
80+
#nullable disable
81+
);
82+
__o = typeof(
83+
#nullable restore
84+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
85+
string
86+
87+
#line default
88+
#line hidden
89+
#nullable disable
90+
);
91+
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
92+
#nullable restore
93+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
94+
_componentValue
95+
96+
#line default
97+
#line hidden
98+
#nullable disable
99+
);
100+
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::Microsoft.AspNetCore.Components.EventCallback<string>>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<string>(this,
101+
global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => _componentValue = __value, _componentValue)));
102+
__builder.AddAttribute(-1, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
103+
}
104+
));
105+
#pragma warning disable BL0005
106+
((global::Test.MyComponent<IComposedInterface, string>)default).
107+
#nullable restore
108+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
109+
Value
110+
111+
#line default
112+
#line hidden
113+
#nullable disable
114+
= default;
115+
#pragma warning restore BL0005
116+
#nullable restore
117+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
118+
__o = typeof(global::Test.MyComponent<,>);
119+
120+
#line default
121+
#line hidden
122+
#nullable disable
123+
}
124+
#pragma warning restore 1998
125+
#nullable restore
126+
#line 4 "x:\dir\subdir\Test\TestComponent.cshtml"
127+
128+
string _componentValue = string.Empty;
129+
130+
#line default
131+
#line hidden
132+
#nullable disable
133+
}
134+
}
135+
#pragma warning restore 1591
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Document -
2+
NamespaceDeclaration - - Test
3+
UsingDirective - (3:1,1 [20] ) - global::System
4+
UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic
5+
UsingDirective - (69:3,1 [25] ) - global::System.Linq
6+
UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks
7+
UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components
8+
ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase -
9+
DesignTimeDirective -
10+
CSharpCode -
11+
IntermediateToken - - CSharp - #pragma warning disable 0414
12+
CSharpCode -
13+
IntermediateToken - - CSharp - private static object __o = null;
14+
CSharpCode -
15+
IntermediateToken - - CSharp - #pragma warning restore 0414
16+
MethodDeclaration - - protected override - void - BuildRenderTree
17+
Component - (0:0,0 [89] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
18+
ComponentTypeArgument - (19:0,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TKey
19+
LazyIntermediateToken - (19:0,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
20+
ComponentTypeArgument - (37:0,37 [18] x:\dir\subdir\Test\TestComponent.cshtml) - TService
21+
LazyIntermediateToken - (37:0,37 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - IComposedInterface
22+
ComponentAttribute - (70:0,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value - AttributeStructure.DoubleQuotes
23+
CSharpExpression -
24+
LazyIntermediateToken - (70:0,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - _componentValue
25+
ComponentAttribute - (70:0,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged - ValueChanged - AttributeStructure.DoubleQuotes
26+
CSharpExpression -
27+
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this,
28+
IntermediateToken - - CSharp - __value => _componentValue = __value
29+
IntermediateToken - - CSharp - , _componentValue)
30+
HtmlContent - (89:0,89 [2] x:\dir\subdir\Test\TestComponent.cshtml)
31+
LazyIntermediateToken - (89:0,89 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
32+
Component - (91:1,0 [89] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
33+
ComponentTypeArgument - (114:1,23 [18] x:\dir\subdir\Test\TestComponent.cshtml) - TService
34+
LazyIntermediateToken - (114:1,23 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - IComposedInterface
35+
ComponentTypeArgument - (140:1,49 [6] x:\dir\subdir\Test\TestComponent.cshtml) - TKey
36+
LazyIntermediateToken - (140:1,49 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - string
37+
ComponentAttribute - (161:1,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value - AttributeStructure.DoubleQuotes
38+
CSharpExpression -
39+
LazyIntermediateToken - (161:1,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - _componentValue
40+
ComponentAttribute - (161:1,70 [15] x:\dir\subdir\Test\TestComponent.cshtml) - ValueChanged - ValueChanged - AttributeStructure.DoubleQuotes
41+
CSharpExpression -
42+
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this,
43+
IntermediateToken - - CSharp - __value => _componentValue = __value
44+
IntermediateToken - - CSharp - , _componentValue)
45+
HtmlContent - (180:1,89 [4] x:\dir\subdir\Test\TestComponent.cshtml)
46+
LazyIntermediateToken - (180:1,89 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
47+
CSharpCode - (191:3,7 [46] x:\dir\subdir\Test\TestComponent.cshtml)
48+
LazyIntermediateToken - (191:3,7 [46] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n string _componentValue = string.Empty;\n
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Source Location: (19:0,19 [6] x:\dir\subdir\Test\TestComponent.cshtml)
2+
|string|
3+
Generated Location: (947:25,19 [6] )
4+
|string|
5+
6+
Source Location: (37:0,37 [18] x:\dir\subdir\Test\TestComponent.cshtml)
7+
|IComposedInterface|
8+
Generated Location: (1155:34,37 [18] )
9+
|IComposedInterface|
10+
11+
Source Location: (70:0,70 [15] x:\dir\subdir\Test\TestComponent.cshtml)
12+
|_componentValue|
13+
Generated Location: (1491:43,70 [15] )
14+
|_componentValue|
15+
16+
Source Location: (63:0,63 [5] x:\dir\subdir\Test\TestComponent.cshtml)
17+
|Value|
18+
Generated Location: (2417:58,63 [5] )
19+
|Value|
20+
21+
Source Location: (114:1,23 [18] x:\dir\subdir\Test\TestComponent.cshtml)
22+
|IComposedInterface|
23+
Generated Location: (2827:75,23 [18] )
24+
|IComposedInterface|
25+
26+
Source Location: (140:1,49 [6] x:\dir\subdir\Test\TestComponent.cshtml)
27+
|string|
28+
Generated Location: (3059:84,49 [6] )
29+
|string|
30+
31+
Source Location: (161:1,70 [15] x:\dir\subdir\Test\TestComponent.cshtml)
32+
|_componentValue|
33+
Generated Location: (3383:93,70 [15] )
34+
|_componentValue|
35+
36+
Source Location: (154:1,63 [5] x:\dir\subdir\Test\TestComponent.cshtml)
37+
|Value|
38+
Generated Location: (4309:108,63 [5] )
39+
|Value|
40+
41+
Source Location: (191:3,7 [46] x:\dir\subdir\Test\TestComponent.cshtml)
42+
|
43+
string _componentValue = string.Empty;
44+
|
45+
Generated Location: (4725:126,7 [46] )
46+
|
47+
string _componentValue = string.Empty;
48+
|
49+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// <auto-generated/>
2+
#pragma warning disable 1591
3+
namespace Test
4+
{
5+
#line hidden
6+
using global::System;
7+
using global::System.Collections.Generic;
8+
using global::System.Linq;
9+
using global::System.Threading.Tasks;
10+
using global::Microsoft.AspNetCore.Components;
11+
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
12+
{
13+
#pragma warning disable 1998
14+
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
15+
{
16+
__builder.OpenComponent<global::Test.MyComponent<IComposedInterface, string>>(0);
17+
__builder.AddComponentParameter(1, "Value", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
18+
#nullable restore
19+
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
20+
_componentValue
21+
22+
#line default
23+
#line hidden
24+
#nullable disable
25+
));
26+
__builder.AddComponentParameter(2, "ValueChanged", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::Microsoft.AspNetCore.Components.EventCallback<string>>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<string>(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => _componentValue = __value, _componentValue))));
27+
__builder.CloseComponent();
28+
__builder.AddMarkupContent(3, "\r\n");
29+
__builder.OpenComponent<global::Test.MyComponent<IComposedInterface, string>>(4);
30+
__builder.AddComponentParameter(5, "Value", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
31+
#nullable restore
32+
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
33+
_componentValue
34+
35+
#line default
36+
#line hidden
37+
#nullable disable
38+
));
39+
__builder.AddComponentParameter(6, "ValueChanged", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::Microsoft.AspNetCore.Components.EventCallback<string>>(global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<string>(this, global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.CreateInferredEventCallback(this, __value => _componentValue = __value, _componentValue))));
40+
__builder.CloseComponent();
41+
}
42+
#pragma warning restore 1998
43+
#nullable restore
44+
#line 4 "x:\dir\subdir\Test\TestComponent.cshtml"
45+
46+
string _componentValue = string.Empty;
47+
48+
#line default
49+
#line hidden
50+
#nullable disable
51+
}
52+
}
53+
#pragma warning restore 1591

0 commit comments

Comments
 (0)