diff --git a/src/Components/Components/src/CascadingTypeParameterAttribute.cs b/src/Components/Components/src/CascadingTypeParameterAttribute.cs
new file mode 100644
index 000000000000..bfd866ce846b
--- /dev/null
+++ b/src/Components/Components/src/CascadingTypeParameterAttribute.cs
@@ -0,0 +1,35 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Components
+{
+ ///
+ /// Denotes the generic type parameter as cascading. This allows generic type inference
+ /// to use this type parameter value automatically on descendants that also have a type
+ /// parameter with the same name.
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
+ public sealed class CascadingTypeParameterAttribute : Attribute
+ {
+ ///
+ /// Constructs an instance of .
+ ///
+ /// The name of the type parameter.
+ public CascadingTypeParameterAttribute(string name)
+ {
+ if (name == null)
+ {
+ throw new ArgumentNullException(nameof(name));
+ }
+
+ Name = name;
+ }
+
+ ///
+ /// Gets the name of the type parameter.
+ ///
+ public string Name { get; }
+ }
+}
diff --git a/src/Components/Components/src/PublicAPI.Unshipped.txt b/src/Components/Components/src/PublicAPI.Unshipped.txt
index 3acbf2de6886..2a3230fb7606 100644
--- a/src/Components/Components/src/PublicAPI.Unshipped.txt
+++ b/src/Components/Components/src/PublicAPI.Unshipped.txt
@@ -7,5 +7,8 @@ Microsoft.AspNetCore.Components.DynamicComponent.Parameters.set -> void
Microsoft.AspNetCore.Components.DynamicComponent.SetParametersAsync(Microsoft.AspNetCore.Components.ParameterView parameters) -> System.Threading.Tasks.Task!
Microsoft.AspNetCore.Components.DynamicComponent.Type.get -> System.Type!
Microsoft.AspNetCore.Components.DynamicComponent.Type.set -> void
+Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute
+Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute.CascadingTypeParameterAttribute(string! name) -> void
+Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute.Name.get -> string!
static Microsoft.AspNetCore.Components.ParameterView.FromDictionary(System.Collections.Generic.IDictionary! parameters) -> Microsoft.AspNetCore.Components.ParameterView
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.DispatchEventAsync(ulong eventHandlerId, Microsoft.AspNetCore.Components.RenderTree.EventFieldInfo? fieldInfo, System.EventArgs! eventArgs) -> System.Threading.Tasks.Task!
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs
index 4e2cd831efef..874e64061184 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentDesignTimeNodeWriter.cs
@@ -418,22 +418,49 @@ public override void WriteComponent(CodeRenderingContext context, ComponentInter
}
else
{
+ var parameters = GetTypeInferenceMethodParameters(node.TypeInferenceNode);
+
+ // If this component is going to cascade any of its generic types, we have to split its type inference
+ // into two parts. First we call an inference method that captures all the parameters in local variables,
+ // then we use those to call the real type inference method that emits the component. The reason for this
+ // is so the captured variables can be used by descendants without re-evaluating the expressions.
+ CodeWriterExtensions.CSharpCodeWritingScope? typeInferenceCaptureScope = null;
+ if (node.Component.SuppliesCascadingGenericParameters())
+ {
+ typeInferenceCaptureScope = context.CodeWriter.BuildScope();
+ context.CodeWriter.Write(node.TypeInferenceNode.FullTypeName);
+ context.CodeWriter.Write(".");
+ context.CodeWriter.Write(node.TypeInferenceNode.MethodName);
+ context.CodeWriter.Write("_CaptureParameters(");
+ var isFirst = true;
+ foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
+ {
+ if (isFirst)
+ {
+ isFirst = false;
+ }
+ else
+ {
+ context.CodeWriter.Write(", ");
+ }
+
+ WriteTypeInferenceMethodParameterInnards(context, parameter);
+ context.CodeWriter.Write(", out var ");
+
+ var variableName = $"__typeInferenceArg_{_scopeStack.Depth}_{parameter.ParameterName}";
+ context.CodeWriter.Write(variableName);
+
+ UseCapturedCascadingGenericParameterVariable(node, parameter, variableName);
+ }
+ context.CodeWriter.WriteLine(");");
+ }
+
// When we're doing type inference, we can't write all of the code inline to initialize
// the component on the builder. We generate a method elsewhere, and then pass all of the information
// to that method. We pass in all of the attribute values + the sequence numbers.
//
// __Blazor.MyComponent.TypeInference.CreateMyComponent_0(__builder, 0, 1, ..., 2, ..., 3, ....);
- // Preserve order of attributes + splats
- var attributes = node.Children.Where(s =>
- {
- return s is ComponentAttributeIntermediateNode || s is SplatIntermediateNode;
- }).ToList();
- var childContents = node.ChildContents.ToList();
- var captures = node.Captures.ToList();
- var setKeys = node.SetKeys.ToList();
- var remaining = attributes.Count + childContents.Count + captures.Count + setKeys.Count;
-
context.CodeWriter.Write(node.TypeInferenceNode.FullTypeName);
context.CodeWriter.Write(".");
context.CodeWriter.Write(node.TypeInferenceNode.MethodName);
@@ -443,76 +470,27 @@ public override void WriteComponent(CodeRenderingContext context, ComponentInter
context.CodeWriter.Write(", ");
context.CodeWriter.Write("-1");
- context.CodeWriter.Write(", ");
- for (var i = 0; i < attributes.Count; i++)
+ foreach (var parameter in parameters)
{
- context.CodeWriter.Write("-1");
context.CodeWriter.Write(", ");
- // Don't type check generics, since we can't actually write the type name.
- // The type checking with happen anyway since we defined a method and we're generating
- // a call to it.
- if (attributes[i] is ComponentAttributeIntermediateNode attribute)
- {
- WriteComponentAttributeInnards(context, attribute, canTypeCheck: false);
- }
- else if (attributes[i] is SplatIntermediateNode splat)
- {
- WriteSplatInnards(context, splat, canTypeCheck: false);
- }
-
- remaining--;
- if (remaining > 0)
+ if (!string.IsNullOrEmpty(parameter.SeqName))
{
+ context.CodeWriter.Write("-1");
context.CodeWriter.Write(", ");
}
- }
- for (var i = 0; i < childContents.Count; i++)
- {
- context.CodeWriter.Write("-1");
- context.CodeWriter.Write(", ");
-
- WriteComponentChildContentInnards(context, childContents[i]);
-
- remaining--;
- if (remaining > 0)
- {
- context.CodeWriter.Write(", ");
- }
+ WriteTypeInferenceMethodParameterInnards(context, parameter);
}
- for (var i = 0; i < setKeys.Count; i++)
- {
- context.CodeWriter.Write("-1");
- context.CodeWriter.Write(", ");
-
- WriteSetKeyInnards(context, setKeys[i]);
-
- remaining--;
- if (remaining > 0)
- {
- context.CodeWriter.Write(", ");
- }
- }
+ context.CodeWriter.Write(");");
+ context.CodeWriter.WriteLine();
- for (var i = 0; i < captures.Count; i++)
+ if (typeInferenceCaptureScope.HasValue)
{
- context.CodeWriter.Write("-1");
- context.CodeWriter.Write(", ");
-
- WriteReferenceCaptureInnards(context, captures[i], shouldTypeCheck: false);
-
- remaining--;
- if (remaining > 0)
- {
- context.CodeWriter.Write(", ");
- }
+ typeInferenceCaptureScope.Value.Dispose();
}
-
- context.CodeWriter.Write(");");
- context.CodeWriter.WriteLine();
}
// We want to generate something that references the Component type to avoid
@@ -540,6 +518,42 @@ public override void WriteComponent(CodeRenderingContext context, ComponentInter
}
}
+ private void WriteTypeInferenceMethodParameterInnards(CodeRenderingContext context, TypeInferenceMethodParameter parameter)
+ {
+ switch (parameter.Source)
+ {
+ case ComponentAttributeIntermediateNode attribute:
+ // Don't type check generics, since we can't actually write the type name.
+ // The type checking with happen anyway since we defined a method and we're generating
+ // a call to it.
+ WriteComponentAttributeInnards(context, attribute, canTypeCheck: false);
+ break;
+ case SplatIntermediateNode splat:
+ WriteSplatInnards(context, splat, canTypeCheck: false);
+ break;
+ case ComponentChildContentIntermediateNode childNode:
+ WriteComponentChildContentInnards(context, childNode);
+ break;
+ case SetKeyIntermediateNode setKey:
+ WriteSetKeyInnards(context, setKey);
+ break;
+ case ReferenceCaptureIntermediateNode capture:
+ WriteReferenceCaptureInnards(context, capture, shouldTypeCheck: false);
+ break;
+ case CascadingGenericTypeParameter syntheticArg:
+ // The value should be populated before we use it, because we emit code for creating ancestors
+ // first, and that's where it's populated. However if this goes wrong somehow, we don't want to
+ // throw, so use a fallback
+ context.CodeWriter.Write(syntheticArg.ValueExpression ?? "default");
+ break;
+ case TypeInferenceCapturedVariable capturedVariable:
+ context.CodeWriter.Write(capturedVariable.VariableName);
+ break;
+ default:
+ throw new InvalidOperationException($"Not implemented: type inference method parameter from source {parameter.Source}");
+ }
+ }
+
public override void WriteComponentAttribute(CodeRenderingContext context, ComponentAttributeIntermediateNode node)
{
if (context == null)
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs
index 09ba98516f55..977cb8cad647 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentGenericTypePass.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
@@ -74,7 +75,12 @@ private void Process(ComponentIntermediateNode node)
//
// Listing all type parameters that exist
var bindings = new Dictionary();
- foreach (var attribute in node.Component.GetTypeParameters())
+ var componentTypeParameters = node.Component.GetTypeParameters().ToList();
+ var supplyCascadingTypeParameters = componentTypeParameters
+ .Where(p => p.IsCascadingTypeParameterProperty())
+ .Select(p => p.Name)
+ .ToList();
+ foreach (var attribute in componentTypeParameters)
{
bindings.Add(attribute.Name, new Binding() { Attribute = attribute, });
}
@@ -88,6 +94,18 @@ private void Process(ComponentIntermediateNode node)
var binding = bindings[typeArgumentNode.TypeParameterName];
binding.Node = typeArgumentNode;
binding.Content = GetContent(typeArgumentNode);
+
+ // Offer this explicit type argument to descendants too
+ if (supplyCascadingTypeParameters.Contains(typeArgumentNode.TypeParameterName))
+ {
+ node.ProvidesCascadingGenericTypes ??= new();
+ node.ProvidesCascadingGenericTypes[typeArgumentNode.TypeParameterName] = new CascadingGenericTypeParameter
+ {
+ GenericTypeNames = new[] { typeArgumentNode.TypeParameterName },
+ ValueType = typeArgumentNode.TypeParameterName,
+ ValueExpression = $"default({binding.Content})",
+ };
+ }
}
if (hasTypeArgumentSpecified)
@@ -118,36 +136,113 @@ private void Process(ComponentIntermediateNode node)
//
// For example, consider a repeater where the generic type is the 'item' type, but the developer has
// not set the items. We won't be able to do type inference on this and so it will just be nonsense.
- var attributes = node.Attributes.Select(a => a.BoundAttribute).Concat(node.ChildContents.Select(c => c.BoundAttribute));
- foreach (var attribute in attributes)
+ foreach (var attribute in node.Attributes)
{
- if (attribute == null)
+ if (attribute != null && TryFindGenericTypeNames(attribute.BoundAttribute, out var typeParameters))
{
- // Will be null for attributes set on the component that don't match a declared component parameter
- continue;
- }
+ var attributeValueIsLambda = _pass.TypeNameFeature.IsLambda(GetContent(attribute));
+ var provideCascadingGenericTypes = new CascadingGenericTypeParameter
+ {
+ GenericTypeNames = typeParameters,
+ ValueType = attribute.BoundAttribute.TypeName,
+ ValueSourceNode = attribute,
+ };
- // Now we need to parse the type name and extract the generic parameters.
- //
- // Two cases;
- // 1. name is a simple identifier like TItem
- // 2. name contains type parameters like Dictionary
- if (!attribute.IsGenericTypedProperty())
- {
- continue;
+ foreach (var typeName in typeParameters)
+ {
+ if (supplyCascadingTypeParameters.Contains(typeName))
+ {
+ // Advertise that this particular inferred generic type is available to descendants.
+ // There might be multiple sources for each generic type, so pick the one that has the
+ // fewest other generic types on it. For example if we could infer from either List
+ // or Dictionary, we prefer List.
+ node.ProvidesCascadingGenericTypes ??= new();
+ if (!node.ProvidesCascadingGenericTypes.TryGetValue(typeName, out var existingValue)
+ || existingValue.GenericTypeNames.Count > typeParameters.Count)
+ {
+ node.ProvidesCascadingGenericTypes[typeName] = provideCascadingGenericTypes;
+ }
+ }
+
+ if (attributeValueIsLambda)
+ {
+ // For attributes whose values are lambdas, we don't know whether or not the value
+ // covers the generic type - it depends on the content of the lambda.
+ // For example, "() => 123" can cover Func, but "() => null" cannot. So we'll
+ // accept cascaded generic types from ancestors if they are compatible with the lambda,
+ // hence we don't remove it from the list of uncovered generic types until after
+ // we try matching against ancestor cascades.
+ if (bindings.TryGetValue(typeName, out var binding))
+ {
+ binding.CoveredByLambda = true;
+ }
+ }
+ else
+ {
+ bindings.Remove(typeName);
+ }
+ }
}
+ }
- var typeParameters = _pass.TypeNameFeature.ParseTypeParameters(attribute.TypeName);
- if (typeParameters.Count == 0)
+ // For any remaining bindings, scan up the hierarchy of ancestor components and try to match them
+ // with a cascaded generic parameter that can cover this one
+ List receivesCascadingGenericTypes = null;
+ foreach (var uncoveredBindingKey in bindings.Keys.ToList())
+ {
+ var uncoveredBinding = bindings[uncoveredBindingKey];
+ foreach (var candidateAncestor in Ancestors.OfType())
{
- bindings.Remove(attribute.TypeName);
+ if (candidateAncestor.ProvidesCascadingGenericTypes != null
+ && candidateAncestor.ProvidesCascadingGenericTypes.TryGetValue(uncoveredBindingKey, out var genericTypeProvider))
+ {
+ // If the parameter value is an expression that includes multiple generic types, we only want
+ // to use it if we want *all* those generic types. That is, a parameter of type MyType
+ // can supply types to a Child, but not to a Child.
+ // This is purely to avoid blowing up the complexity of the implementation here and could be
+ // overcome in the future if we want. We'd need to figure out which extra types are unwanted,
+ // and rewrite them to some unique name, and add that to the generic parameters list of the
+ // inference methods.
+ if (genericTypeProvider.GenericTypeNames.All(GenericTypeIsUsed))
+ {
+ bindings.Remove(uncoveredBindingKey);
+ receivesCascadingGenericTypes ??= new();
+ receivesCascadingGenericTypes.Add(genericTypeProvider);
+
+ // It's sufficient to identify the closest provider for each type parameter
+ break;
+ }
+
+ bool GenericTypeIsUsed(string typeName) => componentTypeParameters
+ .Select(t => t.Name)
+ .Contains(typeName, StringComparer.Ordinal);
+ }
}
- else
+ }
+
+ // There are two remaining sources of possible generic type info which we consider
+ // lower-priority than cascades from ancestors. Since these two sources *may* actually
+ // resolve generic type ambiguities in some cases, we treat them as covering.
+ //
+ // [1] Attributes given as lambda expressions. These are lower priority than ancestor
+ // cascades because in most cases, lambdas don't provide type info
+ foreach (var entryToRemove in bindings.Where(e => e.Value.CoveredByLambda).ToList())
+ {
+ // Treat this binding as covered, because it's possible that the lambda does provide
+ // enough info for type inference to succeed.
+ bindings.Remove(entryToRemove.Key);
+ }
+
+ // [2] Child content parameters, which are nearly always defined as untyped lambdas
+ // (at least, that's what the Razor compiler produces), but can technically be
+ // hardcoded as a RenderFragment and hence actually give type info.
+ foreach (var attribute in node.ChildContents)
+ {
+ if (TryFindGenericTypeNames(attribute.BoundAttribute, out var typeParameters))
{
- for (var i = 0; i < typeParameters.Count; i++)
+ foreach (var typeName in typeParameters)
{
- var typeParameter = typeParameters[i];
- bindings.Remove(typeParameter.ToString());
+ bindings.Remove(typeName);
}
}
}
@@ -169,7 +264,35 @@ private void Process(ComponentIntermediateNode node)
// contains all of the operations on the render tree building. Calling a method to operate on the builder
// will allow the C# compiler to perform type inference.
var documentNode = (DocumentIntermediateNode)Ancestors[Ancestors.Count - 1];
- CreateTypeInferenceMethod(documentNode, node);
+ CreateTypeInferenceMethod(documentNode, node, receivesCascadingGenericTypes);
+ }
+
+ private bool TryFindGenericTypeNames(BoundAttributeDescriptor boundAttribute, out IReadOnlyList typeParameters)
+ {
+ if (boundAttribute == null)
+ {
+ // Will be null for attributes set on the component that don't match a declared component parameter
+ typeParameters = null;
+ return false;
+ }
+
+ if (!boundAttribute.IsGenericTypedProperty())
+ {
+ typeParameters = null;
+ return false;
+ }
+
+ // Now we need to parse the type name and extract the generic parameters.
+ // Two cases;
+ // 1. name is a simple identifier like TItem
+ // 2. name contains type parameters like Dictionary
+ typeParameters = _pass.TypeNameFeature.ParseTypeParameters(boundAttribute.TypeName);
+ if (typeParameters.Count == 0)
+ {
+ typeParameters = new[] { boundAttribute.TypeName };
+ }
+
+ return true;
}
private string GetContent(ComponentTypeArgumentIntermediateNode node)
@@ -177,6 +300,11 @@ private string GetContent(ComponentTypeArgumentIntermediateNode node)
return string.Join(string.Empty, node.FindDescendantNodes().Where(t => t.IsCSharp).Select(t => t.Content));
}
+ private string GetContent(ComponentAttributeIntermediateNode node)
+ {
+ return string.Join(string.Empty, node.FindDescendantNodes().Where(t => t.IsCSharp).Select(t => t.Content));
+ }
+
private static bool ValidateTypeArguments(ComponentIntermediateNode node, Dictionary bindings)
{
var missing = new List();
@@ -270,7 +398,7 @@ private void RewriteTypeNames(TypeNameRewriter rewriter, ComponentIntermediateNo
}
}
- private void CreateTypeInferenceMethod(DocumentIntermediateNode documentNode, ComponentIntermediateNode node)
+ private void CreateTypeInferenceMethod(DocumentIntermediateNode documentNode, ComponentIntermediateNode node, List receivesCascadingGenericTypes)
{
var @namespace = documentNode.FindPrimaryNamespace().Content;
@namespace = string.IsNullOrEmpty(@namespace) ? "__Blazor" : "__Blazor." + @namespace;
@@ -284,6 +412,8 @@ private void CreateTypeInferenceMethod(DocumentIntermediateNode documentNode, Co
// component call site.
MethodName = $"Create{CSharpIdentifier.SanitizeIdentifier(node.TagName)}_{_id++}",
FullTypeName = @namespace + ".TypeInference",
+
+ ReceivesCascadingGenericTypes = receivesCascadingGenericTypes,
};
node.TypeInferenceNode = typeInferenceNode;
@@ -336,6 +466,8 @@ private class Binding
public string Content { get; set; }
public ComponentTypeArgumentIntermediateNode Node { get; set; }
+
+ public bool CoveredByLambda { get; set; }
}
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentMetadata.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentMetadata.cs
index 6a2dd46d2903..4f25d2d86e56 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentMetadata.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentMetadata.cs
@@ -106,6 +106,8 @@ public static class Component
public readonly static string TypeParameterKey = "Components.TypeParameter";
+ public readonly static string TypeParameterIsCascadingKey = "Components.TypeParameterIsCascading";
+
public readonly static string NameMatchKey = "Components.NameMatch";
public readonly static string FullyQualifiedNameMatch = "Components.FullyQualifiedNameMatch";
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs
index df21a531fa74..858913ea63c5 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentNodeWriter.cs
@@ -54,10 +54,7 @@ public override void WriteComponentTypeInferenceMethod(CodeRenderingContext cont
throw new ArgumentNullException(nameof(node));
}
- // This is ugly because CodeWriter doesn't allow us to erase, but we need to comma-delimit. So we have to
- // materizalize something can iterate, or use string.Join. We'll need this multiple times, so materializing
- // it.
- var parameters = GetParameterDeclarations();
+ var parameters = GetTypeInferenceMethodParameters(node);
// This is really similar to the code in WriteComponentAttribute and WriteComponentChildContent - except simpler because
// attributes and child contents look like variables.
@@ -82,7 +79,6 @@ public override void WriteComponentTypeInferenceMethod(CodeRenderingContext cont
writer.Write("public static void ");
writer.Write(node.MethodName);
-
writer.Write("<");
writer.Write(string.Join(", ", node.Component.Component.GetTypeParameters().Select(a => a.Name)));
writer.Write(">");
@@ -102,13 +98,16 @@ public override void WriteComponentTypeInferenceMethod(CodeRenderingContext cont
for (var i = 0; i < parameters.Count; i++)
{
- writer.Write("int ");
- writer.Write(parameters[i].seqName);
+ if (!string.IsNullOrEmpty(parameters[i].SeqName))
+ {
+ writer.Write("int ");
+ writer.Write(parameters[i].SeqName);
+ writer.Write(", ");
+ }
- writer.Write(", ");
- writer.Write(parameters[i].typeName);
+ writer.Write(parameters[i].TypeName);
writer.Write(" ");
- writer.Write(parameters[i].parameterName);
+ writer.Write(parameters[i].ParameterName);
if (i < parameters.Count - 1)
{
@@ -132,131 +131,253 @@ public override void WriteComponentTypeInferenceMethod(CodeRenderingContext cont
context.CodeWriter.Write(");");
context.CodeWriter.WriteLine();
- var index = 0;
+ foreach (var parameter in parameters)
+ {
+ switch (parameter.Source)
+ {
+ case ComponentAttributeIntermediateNode attribute:
+ context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
+ context.CodeWriter.Write(parameter.SeqName);
+ context.CodeWriter.Write(", ");
+
+ context.CodeWriter.Write($"\"{attribute.AttributeName}\"");
+ context.CodeWriter.Write(", ");
+
+ context.CodeWriter.Write(parameter.ParameterName);
+ context.CodeWriter.WriteEndMethodInvocation();
+ break;
+
+ case SplatIntermediateNode:
+ context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddMultipleAttributes);
+ context.CodeWriter.Write(parameter.SeqName);
+ context.CodeWriter.Write(", ");
+
+ context.CodeWriter.Write(parameter.ParameterName);
+ context.CodeWriter.WriteEndMethodInvocation();
+ break;
+
+ case ComponentChildContentIntermediateNode childContent:
+ context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
+ context.CodeWriter.Write(parameter.SeqName);
+ context.CodeWriter.Write(", ");
+
+ context.CodeWriter.Write($"\"{childContent.AttributeName}\"");
+ context.CodeWriter.Write(", ");
+
+ context.CodeWriter.Write(parameter.ParameterName);
+ context.CodeWriter.WriteEndMethodInvocation();
+ break;
+
+ case SetKeyIntermediateNode:
+ context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.SetKey);
+ context.CodeWriter.Write(parameter.ParameterName);
+ context.CodeWriter.WriteEndMethodInvocation();
+ break;
+
+ case ReferenceCaptureIntermediateNode capture:
+ context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, capture.IsComponentCapture ? ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture : ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture);
+ context.CodeWriter.Write(parameter.SeqName);
+ context.CodeWriter.Write(", ");
+
+ var cast = capture.IsComponentCapture ? $"({capture.ComponentCaptureTypeName})" : string.Empty;
+ context.CodeWriter.Write($"(__value) => {{ {parameter.ParameterName}({cast}__value); }}");
+ context.CodeWriter.WriteEndMethodInvocation();
+ break;
+
+ case CascadingGenericTypeParameter:
+ // We only use the synthetic cascading parameters for type inference
+ break;
+
+ default:
+ throw new InvalidOperationException($"Not implemented: type inference method parameter from source {parameter.Source}");
+ }
+ }
- // Preserve order of attributes and splat.
- foreach (var child in node.Component.Children)
+ context.CodeWriter.WriteInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.CloseComponent);
+
+ writer.WriteLine("}");
+
+ if (node.Component.Component.SuppliesCascadingGenericParameters())
{
- if (child is ComponentAttributeIntermediateNode attribute)
+ // If this component cascades any generic parameters, we'll need to be able to capture its type inference
+ // args at the call site. The point of this is to ensure that:
+ //
+ // [1] We only evaluate each expression once
+ // [2] We evaluate them in the correct order matching the developer's source
+ // [3] We can even make variables for lambdas or other expressions that can't just be assigned to implicitly-typed vars.
+ //
+ // We do that by emitting a method like the following. It has exactly the same generic type inference
+ // characteristics as the regular CreateFoo_0 method emitted earlier
+ //
+ // public static void CreateFoo_0_CaptureParameters(T1 __arg0, out T1 __arg0_out, global::System.Collections.Generic.List __arg1, out global::System.Collections.Generic.List __arg1_out, int __seq2, string __arg2, out string __arg2_out)
+ // {
+ // __arg0_out = __arg0;
+ // __arg1_out = __arg1;
+ // __arg2_out = __arg2;
+ // }
+ //
+ writer.WriteLine();
+ writer.Write("public static void ");
+ writer.Write(node.MethodName);
+ writer.Write("_CaptureParameters<");
+ writer.Write(string.Join(", ", node.Component.Component.GetTypeParameters().Select(a => a.Name)));
+ writer.Write(">");
+
+ writer.Write("(");
+ var isFirst = true;
+ foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
{
- context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
- context.CodeWriter.Write(parameters[index].seqName);
- context.CodeWriter.Write(", ");
+ if (isFirst)
+ {
+ isFirst = false;
+ }
+ else
+ {
+ writer.Write(", ");
+ }
- context.CodeWriter.Write($"\"{attribute.AttributeName}\"");
- context.CodeWriter.Write(", ");
+ writer.Write(parameter.TypeName);
+ writer.Write(" ");
+ writer.Write(parameter.ParameterName);
+ writer.Write(", out ");
+ writer.Write(parameter.TypeName);
+ writer.Write(" ");
+ writer.Write(parameter.ParameterName);
+ writer.Write("_out");
+ }
- context.CodeWriter.Write(parameters[index].parameterName);
- context.CodeWriter.WriteEndMethodInvocation();
- index++;
+ writer.WriteLine(")");
+ writer.WriteLine("{");
+ foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
+ {
+ writer.Write(" ");
+ writer.Write(parameter.ParameterName);
+ writer.Write("_out = ");
+ writer.Write(parameter.ParameterName);
+ writer.WriteLine(";");
}
- else if (child is SplatIntermediateNode)
+ writer.WriteLine("}");
+ }
+ }
+
+ protected List GetTypeInferenceMethodParameters(ComponentTypeInferenceMethodIntermediateNode node)
+ {
+ var p = new List();
+
+ // Preserve order between attributes and splats
+ foreach (var child in node.Component.Children)
+ {
+ if (child is ComponentAttributeIntermediateNode attribute)
{
- context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddMultipleAttributes);
- context.CodeWriter.Write(parameters[index].seqName);
- context.CodeWriter.Write(", ");
+ string typeName;
+ if (attribute.GloballyQualifiedTypeName != null)
+ {
+ typeName = attribute.GloballyQualifiedTypeName;
+ }
+ else
+ {
+ typeName = attribute.TypeName;
+ if (attribute.BoundAttribute != null && !attribute.BoundAttribute.IsGenericTypedProperty())
+ {
+ typeName = "global::" + typeName;
+ }
+ }
- context.CodeWriter.Write(parameters[index].parameterName);
- context.CodeWriter.WriteEndMethodInvocation();
- index++;
+ p.Add(new TypeInferenceMethodParameter($"__seq{p.Count}", typeName, $"__arg{p.Count}", usedForTypeInference: true, attribute));
+ }
+ else if (child is SplatIntermediateNode splat)
+ {
+ var typeName = ComponentsApi.AddMultipleAttributesTypeFullName;
+ p.Add(new TypeInferenceMethodParameter($"__seq{p.Count}", typeName, $"__arg{p.Count}", usedForTypeInference: false, splat));
}
}
foreach (var childContent in node.Component.ChildContents)
{
- context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.AddAttribute);
- context.CodeWriter.Write(parameters[index].seqName);
- context.CodeWriter.Write(", ");
-
- context.CodeWriter.Write($"\"{childContent.AttributeName}\"");
- context.CodeWriter.Write(", ");
-
- context.CodeWriter.Write(parameters[index].parameterName);
- context.CodeWriter.WriteEndMethodInvocation();
-
- index++;
+ var typeName = childContent.TypeName;
+ if (childContent.BoundAttribute != null && !childContent.BoundAttribute.IsGenericTypedProperty())
+ {
+ typeName = "global::" + typeName;
+ }
+ p.Add(new TypeInferenceMethodParameter($"__seq{p.Count}", typeName, $"__arg{p.Count}", usedForTypeInference: false, childContent));
}
- foreach (var setKey in node.Component.SetKeys)
+ foreach (var capture in node.Component.SetKeys)
{
- context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.SetKey);
- context.CodeWriter.Write(parameters[index].parameterName);
- context.CodeWriter.WriteEndMethodInvocation();
-
- index++;
+ p.Add(new TypeInferenceMethodParameter($"__seq{p.Count}", "object", $"__arg{p.Count}", usedForTypeInference: false, capture));
}
foreach (var capture in node.Component.Captures)
{
- context.CodeWriter.WriteStartInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, capture.IsComponentCapture ? ComponentsApi.RenderTreeBuilder.AddComponentReferenceCapture : ComponentsApi.RenderTreeBuilder.AddElementReferenceCapture);
- context.CodeWriter.Write(parameters[index].seqName);
- context.CodeWriter.Write(", ");
-
- var cast = capture.IsComponentCapture ? $"({capture.ComponentCaptureTypeName})" : string.Empty;
- context.CodeWriter.Write($"(__value) => {{ {parameters[index].parameterName}({cast}__value); }}");
- context.CodeWriter.WriteEndMethodInvocation();
-
- index++;
+ // The capture type name should already contain the global:: prefix.
+ p.Add(new TypeInferenceMethodParameter($"__seq{p.Count}", capture.TypeName, $"__arg{p.Count}", usedForTypeInference: false, capture));
}
- context.CodeWriter.WriteInstanceMethodInvocation(ComponentsApi.RenderTreeBuilder.BuilderParameter, ComponentsApi.RenderTreeBuilder.CloseComponent);
-
- writer.WriteLine("}");
-
- List<(string seqName, string typeName, string parameterName)> GetParameterDeclarations()
+ // Insert synthetic args for cascaded type inference at the start of the list
+ // We do this last so that the indices above aren't affected
+ if (node.ReceivesCascadingGenericTypes != null)
{
- var p = new List<(string seqName, string typeName, string parameterName)>();
-
- // Preserve order between attributes and splats
- foreach (var child in node.Component.Children)
+ var i = 0;
+ foreach (var cascadingGenericType in node.ReceivesCascadingGenericTypes)
{
- if (child is ComponentAttributeIntermediateNode attribute)
- {
- string typeName;
- if (attribute.GloballyQualifiedTypeName != null)
- {
- typeName = attribute.GloballyQualifiedTypeName;
- }
- else
- {
- typeName = attribute.TypeName;
- if (attribute.BoundAttribute != null && !attribute.BoundAttribute.IsGenericTypedProperty())
- {
- typeName = "global::" + typeName;
- }
- }
-
- p.Add(($"__seq{p.Count}", typeName, $"__arg{p.Count}"));
- }
- else if (child is SplatIntermediateNode splat)
- {
- var typeName = ComponentsApi.AddMultipleAttributesTypeFullName;
- p.Add(($"__seq{p.Count}", typeName, $"__arg{p.Count}"));
- }
+ p.Insert(i, new TypeInferenceMethodParameter(null, cascadingGenericType.ValueType, $"__syntheticArg{i}", usedForTypeInference: true, cascadingGenericType));
+ i++;
}
+ }
+
+ return p;
+ }
- foreach (var childContent in node.Component.ChildContents)
+ protected static void UseCapturedCascadingGenericParameterVariable(ComponentIntermediateNode node, TypeInferenceMethodParameter parameter, string variableName)
+ {
+ // If this captured variable corresponds to a generic type we want to cascade to
+ // descendants, supply that info to descendants
+ if (node.ProvidesCascadingGenericTypes != null)
+ {
+ foreach (var cascadeGeneric in node.ProvidesCascadingGenericTypes.Values)
{
- var typeName = childContent.TypeName;
- if (childContent.BoundAttribute != null && !childContent.BoundAttribute.IsGenericTypedProperty())
+ if (cascadeGeneric.ValueSourceNode == parameter.Source)
{
- typeName = "global::" + typeName;
+ cascadeGeneric.ValueExpression = variableName;
}
- p.Add(($"__seq{p.Count}", typeName, $"__arg{p.Count}"));
}
+ }
- foreach (var capture in node.Component.SetKeys)
- {
- p.Add(($"__seq{p.Count}", "object", $"__arg{p.Count}"));
- }
+ // Since we've now evaluated and captured this expression, use the variable
+ // instead of the expression from now on
+ parameter.ReplaceSourceWithCapturedVariable(variableName);
+ }
- foreach (var capture in node.Component.Captures)
- {
- // The capture type name should already contain the global:: prefix.
- p.Add(($"__seq{p.Count}", capture.TypeName, $"__arg{p.Count}"));
- }
+ protected class TypeInferenceMethodParameter
+ {
+ public string SeqName { get; private set; }
+ public string TypeName { get; private set; }
+ public string ParameterName { get; private set; }
+ public bool UsedForTypeInference { get; private set; }
+ public object Source { get; private set; }
- return p;
+ public TypeInferenceMethodParameter(string seqName, string typeName, string parameterName, bool usedForTypeInference, object source)
+ {
+ SeqName = seqName;
+ TypeName = typeName;
+ ParameterName = parameterName;
+ UsedForTypeInference = usedForTypeInference;
+ Source = source;
+ }
+
+ public void ReplaceSourceWithCapturedVariable(string variableName)
+ {
+ Source = new TypeInferenceCapturedVariable(variableName);
+ }
+ }
+
+ protected class TypeInferenceCapturedVariable
+ {
+ public string VariableName { get; private set; }
+
+ public TypeInferenceCapturedVariable(string variableName)
+ {
+ VariableName = variableName;
}
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs
index eeb14f021887..c18d4937fa91 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentRuntimeNodeWriter.cs
@@ -404,22 +404,49 @@ public override void WriteComponent(CodeRenderingContext context, ComponentInter
}
else
{
+ var parameters = GetTypeInferenceMethodParameters(node.TypeInferenceNode);
+
+ // If this component is going to cascade any of its generic types, we have to split its type inference
+ // into two parts. First we call an inference method that captures all the parameters in local variables,
+ // then we use those to call the real type inference method that emits the component. The reason for this
+ // is so the captured variables can be used by descendants without re-evaluating the expressions.
+ CodeWriterExtensions.CSharpCodeWritingScope? typeInferenceCaptureScope = null;
+ if (node.Component.SuppliesCascadingGenericParameters())
+ {
+ typeInferenceCaptureScope = context.CodeWriter.BuildScope();
+ context.CodeWriter.Write(node.TypeInferenceNode.FullTypeName);
+ context.CodeWriter.Write(".");
+ context.CodeWriter.Write(node.TypeInferenceNode.MethodName);
+ context.CodeWriter.Write("_CaptureParameters(");
+ var isFirst = true;
+ foreach (var parameter in parameters.Where(p => p.UsedForTypeInference))
+ {
+ if (isFirst)
+ {
+ isFirst = false;
+ }
+ else
+ {
+ context.CodeWriter.Write(", ");
+ }
+
+ WriteTypeInferenceMethodParameterInnards(context, parameter);
+ context.CodeWriter.Write(", out var ");
+
+ var variableName = $"__typeInferenceArg_{_scopeStack.Depth}_{parameter.ParameterName}";
+ context.CodeWriter.Write(variableName);
+
+ UseCapturedCascadingGenericParameterVariable(node, parameter, variableName);
+ }
+ context.CodeWriter.WriteLine(");");
+ }
+
// When we're doing type inference, we can't write all of the code inline to initialize
// the component on the builder. We generate a method elsewhere, and then pass all of the information
// to that method. We pass in all of the attribute values + the sequence numbers.
//
// __Blazor.MyComponent.TypeInference.CreateMyComponent_0(builder, 0, 1, ..., 2, ..., 3, ...);
- // Preserve order of attributes and splats
- var attributes = node.Children.Where(n =>
- {
- return n is ComponentAttributeIntermediateNode || n is SplatIntermediateNode;
- }).ToList();
- var childContents = node.ChildContents.ToList();
- var captures = node.Captures.ToList();
- var setKeys = node.SetKeys.ToList();
- var remaining = attributes.Count + childContents.Count + captures.Count + setKeys.Count;
-
context.CodeWriter.Write(node.TypeInferenceNode.FullTypeName);
context.CodeWriter.Write(".");
context.CodeWriter.Write(node.TypeInferenceNode.MethodName);
@@ -429,76 +456,70 @@ public override void WriteComponent(CodeRenderingContext context, ComponentInter
context.CodeWriter.Write(", ");
context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
- context.CodeWriter.Write(", ");
- for (var i = 0; i < attributes.Count; i++)
+ foreach (var parameter in parameters)
{
- context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
context.CodeWriter.Write(", ");
- // Don't type check generics, since we can't actually write the type name.
- // The type checking with happen anyway since we defined a method and we're generating
- // a call to it.
- if (attributes[i] is ComponentAttributeIntermediateNode attribute)
- {
- WriteComponentAttributeInnards(context, attribute, canTypeCheck: false);
- }
- else if (attributes[i] is SplatIntermediateNode splat)
- {
- WriteSplatInnards(context, splat, canTypeCheck: false);
- }
-
- remaining--;
- if (remaining > 0)
+ if (!string.IsNullOrEmpty(parameter.SeqName))
{
+ context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
context.CodeWriter.Write(", ");
}
- }
-
- for (var i = 0; i < childContents.Count; i++)
- {
- context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
- context.CodeWriter.Write(", ");
-
- WriteComponentChildContentInnards(context, childContents[i]);
- remaining--;
- if (remaining > 0)
- {
- context.CodeWriter.Write(", ");
- }
+ WriteTypeInferenceMethodParameterInnards(context, parameter);
}
- for (var i = 0; i < setKeys.Count; i++)
- {
- context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
- context.CodeWriter.Write(", ");
-
- WriteSetKeyInnards(context, setKeys[i]);
-
- remaining--;
- if (remaining > 0)
- {
- context.CodeWriter.Write(", ");
- }
- }
+ context.CodeWriter.Write(");");
+ context.CodeWriter.WriteLine();
- for (var i = 0; i < captures.Count; i++)
+ if (typeInferenceCaptureScope.HasValue)
{
- context.CodeWriter.Write((_sourceSequence++).ToString(CultureInfo.InvariantCulture));
- context.CodeWriter.Write(", ");
-
- WriteReferenceCaptureInnards(context, captures[i], shouldTypeCheck: false);
-
- remaining--;
- if (remaining > 0)
+ foreach (var localToClear in parameters.Select(p => p.Source).OfType())
{
- context.CodeWriter.Write(", ");
+ // Ensure we're not interfering with the GC lifetime of these captured values
+ // We don't need the values any longer (code in closures only uses its types for compile-time inference)
+ context.CodeWriter.Write(localToClear.VariableName);
+ context.CodeWriter.WriteLine(" = default;");
}
+ typeInferenceCaptureScope.Value.Dispose();
}
+ }
+ }
- context.CodeWriter.Write(");");
- context.CodeWriter.WriteLine();
+ private void WriteTypeInferenceMethodParameterInnards(CodeRenderingContext context, TypeInferenceMethodParameter parameter)
+ {
+ switch (parameter.Source)
+ {
+ case ComponentAttributeIntermediateNode attribute:
+ // Don't type check generics, since we can't actually write the type name.
+ // The type checking with happen anyway since we defined a method and we're generating
+ // a call to it.
+ WriteComponentAttributeInnards(context, attribute, canTypeCheck: false);
+ break;
+ case SplatIntermediateNode splat:
+ WriteSplatInnards(context, splat, canTypeCheck: false);
+ break;
+ case ComponentChildContentIntermediateNode childNode:
+ WriteComponentChildContentInnards(context, childNode);
+ break;
+ case SetKeyIntermediateNode setKey:
+ WriteSetKeyInnards(context, setKey);
+ break;
+ case ReferenceCaptureIntermediateNode capture:
+ WriteReferenceCaptureInnards(context, capture, shouldTypeCheck: false);
+ break;
+ case CascadingGenericTypeParameter syntheticArg:
+ // The value should be populated before we use it, because we emit code for creating ancestors
+ // first, and that's where it's populated. However if this goes wrong somehow, we don't want to
+ // throw, so use a fallback
+ context.CodeWriter.Write(syntheticArg.ValueExpression ?? "default");
+ break;
+ case TypeInferenceCapturedVariable capturedVariable:
+ context.CodeWriter.Write(capturedVariable.VariableName);
+ break;
+ default:
+ throw new InvalidOperationException($"Not implemented: type inference method parameter from source {parameter.Source}");
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentsApi.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentsApi.cs
index 92d54a258236..6e43c70490d7 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentsApi.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ComponentsApi.cs
@@ -158,5 +158,10 @@ public static class BindConverter
public static readonly string FullTypeName = "Microsoft.AspNetCore.Components.BindConverter";
public static readonly string FormatValue = "Microsoft.AspNetCore.Components.BindConverter.FormatValue";
}
+
+ public static class CascadingTypeParameterAttribute
+ {
+ public static readonly string MetadataName = "Microsoft.AspNetCore.Components.CascadingTypeParameterAttribute";
+ }
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScopeStack.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScopeStack.cs
index f1d72f87632f..afbb17b4532a 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScopeStack.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/ScopeStack.cs
@@ -19,6 +19,8 @@ internal class ScopeStack
public string BuilderVarName { get; private set; } = ComponentsApi.RenderTreeBuilder.BuilderParameter;
+ public int Depth => _stack.Count;
+
public void OpenComponentScope(CodeRenderingContext context, string name, string parameterName)
{
var scope = new ScopeEntry(name, ScopeKind.Component);
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperBoundAttributeDescriptorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperBoundAttributeDescriptorExtensions.cs
index 11c626fc9a1c..d603289c85c6 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperBoundAttributeDescriptorExtensions.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperBoundAttributeDescriptorExtensions.cs
@@ -63,6 +63,18 @@ public static bool IsTypeParameterProperty(this BoundAttributeDescriptor attribu
string.Equals(value, bool.TrueString);
}
+ public static bool IsCascadingTypeParameterProperty(this BoundAttributeDescriptor attribute)
+ {
+ if (attribute == null)
+ {
+ throw new ArgumentNullException(nameof(attribute));
+ }
+
+ return
+ attribute.Metadata.TryGetValue(ComponentMetadata.Component.TypeParameterIsCascadingKey, out var value) &&
+ string.Equals(value, bool.TrueString);
+ }
+
public static bool IsWeaklyTyped(this BoundAttributeDescriptor attribute)
{
if (attribute == null)
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperDescriptorExtensions.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperDescriptorExtensions.cs
index 2a732e612cae..0ed20565ae6a 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperDescriptorExtensions.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Components/TagHelperDescriptorExtensions.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
namespace Microsoft.AspNetCore.Razor.Language.Components
{
@@ -295,5 +296,21 @@ public static IEnumerable GetTypeParameters(this TagHe
}
}
}
+
+ ///
+ /// Gets a flag that indicates whether the corresponding component supplies any cascading
+ /// generic type parameters to descendants.
+ ///
+ /// The .
+ /// True if it does supply one or more generic type parameters to descendants; false otherwise.
+ public static bool SuppliesCascadingGenericParameters(this TagHelperDescriptor tagHelper)
+ {
+ if (tagHelper == null)
+ {
+ throw new ArgumentNullException(nameof(tagHelper));
+ }
+
+ return tagHelper.BoundAttributes.Any(a => a.IsCascadingTypeParameterProperty());
+ }
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/CascadingGenericTypeParameter.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/CascadingGenericTypeParameter.cs
new file mode 100644
index 000000000000..87e71222587c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/CascadingGenericTypeParameter.cs
@@ -0,0 +1,34 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+
+namespace Microsoft.AspNetCore.Razor.Language.Intermediate
+{
+ public sealed class CascadingGenericTypeParameter
+ {
+ ///
+ /// Gets or sets the type parameter names covered by the value type, e.g., TKey and TItem
+ ///
+ public IReadOnlyCollection GenericTypeNames { get; set; }
+
+ ///
+ /// Gets or sets a that supplies content for
+ /// . In the case of explicitly-specified generic parameters, this
+ /// will be null.
+ ///
+ internal ComponentAttributeIntermediateNode ValueSourceNode { get; set; }
+
+ ///
+ /// Gets or sets the type of , e.g., Dictionary[TKey, TItem].
+ ///
+ internal string ValueType { get; set; }
+
+ ///
+ /// Gets or sets an expression defining the type of the generic parameter. In the case of inferred
+ /// generic parameters, this will only be populated once a variable is emitted corresponding to
+ /// .
+ ///
+ internal string ValueExpression { get; set; }
+ }
+}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentIntermediateNode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentIntermediateNode.cs
index cfe7c3a276e2..95c117f6b6cd 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentIntermediateNode.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentIntermediateNode.cs
@@ -36,6 +36,12 @@ public sealed class ComponentIntermediateNode : IntermediateNode
// if this component call site requires type inference.
public ComponentTypeInferenceMethodIntermediateNode TypeInferenceNode { get; set; }
+ ///
+ /// Gets a dictionary (or null) that advertises any type arguments that are available
+ /// for use by descendants within the same tree.
+ ///
+ public Dictionary ProvidesCascadingGenericTypes { get; set; }
+
public string TypeName { get; set; }
public override void Accept(IntermediateNodeVisitor visitor)
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentTypeInferenceMethodIntermediateNode.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentTypeInferenceMethodIntermediateNode.cs
index 35340f0172e0..4cf2f1847f45 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentTypeInferenceMethodIntermediateNode.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/Intermediate/ComponentTypeInferenceMethodIntermediateNode.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
+using System.Collections.Generic;
namespace Microsoft.AspNetCore.Razor.Language.Intermediate
{
@@ -27,6 +28,12 @@ public sealed class ComponentTypeInferenceMethodIntermediateNode : IntermediateN
///
public string MethodName { get; set; }
+ ///
+ /// Gets a list (or null) describing additional arguments for type inference.
+ /// These are populated from ancestor components that choose to cascade their type parameters.
+ ///
+ public List ReceivesCascadingGenericTypes { get; set; }
+
public override void Accept(IntermediateNodeVisitor visitor)
{
if (visitor == null)
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/PublicAPI.Unshipped.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/PublicAPI.Unshipped.txt
index 7dc5c58110bf..15ad64837f8a 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/PublicAPI.Unshipped.txt
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/PublicAPI.Unshipped.txt
@@ -1 +1,9 @@
#nullable enable
+Microsoft.AspNetCore.Razor.Language.Intermediate.CascadingGenericTypeParameter
+Microsoft.AspNetCore.Razor.Language.Intermediate.CascadingGenericTypeParameter.CascadingGenericTypeParameter() -> void
+~Microsoft.AspNetCore.Razor.Language.Intermediate.CascadingGenericTypeParameter.GenericTypeNames.get -> System.Collections.Generic.IReadOnlyCollection
+~Microsoft.AspNetCore.Razor.Language.Intermediate.CascadingGenericTypeParameter.GenericTypeNames.set -> void
+~Microsoft.AspNetCore.Razor.Language.Intermediate.ComponentIntermediateNode.ProvidesCascadingGenericTypes.get -> System.Collections.Generic.Dictionary
+~Microsoft.AspNetCore.Razor.Language.Intermediate.ComponentIntermediateNode.ProvidesCascadingGenericTypes.set -> void
+~Microsoft.AspNetCore.Razor.Language.Intermediate.ComponentTypeInferenceMethodIntermediateNode.ReceivesCascadingGenericTypes.get -> System.Collections.Generic.List
+~Microsoft.AspNetCore.Razor.Language.Intermediate.ComponentTypeInferenceMethodIntermediateNode.ReceivesCascadingGenericTypes.set -> void
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TypeNameFeature.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TypeNameFeature.cs
index cecf937f77da..11b9028525d7 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TypeNameFeature.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/src/TypeNameFeature.cs
@@ -1,4 +1,4 @@
-// Copyright (c) .NET Foundation. All rights reserved.
+// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
@@ -14,5 +14,7 @@ internal abstract class TypeNameFeature : RazorEngineFeatureBase
public abstract TypeNameRewriter CreateGenericTypeRewriter(Dictionary bindings);
public abstract TypeNameRewriter CreateGlobalQualifiedTypeNameRewriter(ICollection ignore);
+
+ public abstract bool IsLambda(string expression);
}
}
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs
index 8f23ea01ec59..97bd2f572201 100644
--- a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/IntegrationTests/ComponentCodeGenerationTestBase.cs
@@ -3152,6 +3152,544 @@ public class MyComponent : ComponentBase
CompileToAssembly(generated);
}
+ [Fact]
+ public void ChildComponent_Generic_Explicit_Cascaded()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_Explicit_OverrideCascade()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_Explicit_NotCascaded()
+ {
+ // The point of this test is to show that, without [CascadingTypeParameter], we don't cascade
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+
+ var diagnostic = Assert.Single(generated.Diagnostics);
+ Assert.Same(ComponentDiagnosticFactory.GenericComponentTypeInferenceUnderspecified.Id, diagnostic.Id);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_Cascaded()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+
+ var diagnostic = Assert.Single(generated.Diagnostics);
+ Assert.Same(ComponentDiagnosticFactory.GenericComponentMissingTypeArgument.Id, diagnostic.Id);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey()
+ {
+ // This is an integration test to show that our type inference code doesn't
+ // have bad interactions with some of the other more complicated transformations
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ [Parameter(CaptureUnmatchedValues = true)] public IDictionary OtherAttributes { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+@{ var parentKey = new object(); var childKey = new object(); }
+())"">
+
+");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_MultiLayerCascaded()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Ancestor : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Passthrough : ComponentBase
+ {
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Child : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class TreeNode : ComponentBase
+ {
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ [Parameter] public TItem Item { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+
+
+
+
+
+
+
+");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_OverrideCascade()
+ {
+ // This test is to show that, even if an ancestor is trying to cascade its generic types,
+ // a descendant can still override that through inference
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ [Parameter] public TItem OverrideParam { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_NotCascaded()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+
+ var diagnostic = Assert.Single(generated.Diagnostics);
+ Assert.Same(ComponentDiagnosticFactory.GenericComponentTypeInferenceUnderspecified.Id, diagnostic.Id);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">@context.Year");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_CascadedWithLambda()
+ {
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.IEnumerable Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ [Parameter] public System.Func SomeLambda { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())""> x.Year)"" />");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes()
+ {
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using System.Collections.Generic;
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TKey))]
+ [CascadingTypeParameter(nameof(TValue))]
+ [CascadingTypeParameter(nameof(TOther))]
+ public class Parent : ComponentBase
+ {
+ [Parameter] public Dictionary Data { get; set; }
+ [Parameter] public TOther Other { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Child : ComponentBase
+ {
+ [Parameter] public ICollection ChildOnlyItems { get; set; }
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"" Other=""@DateTime.MinValue"">
+
+");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic()
+ {
+ // It would succeed if you changed this to Column, or if the Grid took a parameter
+ // whose type included TItem and not TUnrelated. It just doesn't work if the only inference parameters
+ // also include unrelated generic types, because the inference methods we generate don't know what
+ // to do with extra type parameters. It would be nice just to ignore them, but at the very least we
+ // have to rewrite their names to avoid clashes and figure out whether multiple unrelated generic
+ // types with the same name should be rewritten to the same name or unique names.
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TItem))]
+ [CascadingTypeParameter(nameof(TUnrelated))]
+ public class Grid : ComponentBase
+ {
+ [Parameter] public System.Collections.Generic.Dictionary Items { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Column : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+())"">");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+
+ var diagnostic = Assert.Single(generated.Diagnostics);
+ Assert.Same(ComponentDiagnosticFactory.GenericComponentTypeInferenceUnderspecified.Id, diagnostic.Id);
+ }
+
+ [Fact]
+ public void ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors()
+ {
+
+ // Arrange
+ AdditionalSyntaxTrees.Add(Parse(@"
+using Microsoft.AspNetCore.Components;
+
+namespace Test
+{
+ [CascadingTypeParameter(nameof(TOne))]
+ public class ParentOne : ComponentBase
+ {
+ [Parameter] public TOne Value { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ [CascadingTypeParameter(nameof(TTwo))]
+ public class ParentTwo : ComponentBase
+ {
+ [Parameter] public TTwo Value { get; set; }
+ [Parameter] public RenderFragment ChildContent { get; set; }
+ }
+
+ public class Child : ComponentBase
+ {
+ }
+}
+"));
+
+ // Act
+ var generated = CompileToCSharp(@"
+
+
+
+
+");
+
+ // Assert
+ AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
+ AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
+ CompileToAssembly(generated);
+ }
+
[Fact]
public void ChildComponent_GenericWeaklyTypedAttribute()
{
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.codegen.cs
new file mode 100644
index 000000000000..91c9ca28f800
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.codegen.cs
@@ -0,0 +1,88 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ __o = typeof(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __o = Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_0(__builder2, -1, default(DateTime));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, default(DateTime));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateColumn_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TItem __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TItem __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.ir.txt
new file mode 100644
index 000000000000..edc77acc7713
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.ir.txt
@@ -0,0 +1,29 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [85] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (58:0,58 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ Component - (68:0,68 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentTypeArgument - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
+ LazyIntermediateToken - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime
+ ComponentAttribute - (30:0,30 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (31:0,31 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.mappings.txt
new file mode 100644
index 000000000000..a30a4b4e995c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_Cascaded/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime|
+Generated Location: (892:25,13 [8] )
+|DateTime|
+
+Source Location: (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (1214:34,32 [23] )
+|Array.Empty()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.codegen.cs
new file mode 100644
index 000000000000..71ced866d3db
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.codegen.cs
@@ -0,0 +1,75 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ __o = typeof(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __o = Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_0(__builder2, -1);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateColumn_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.diagnostics.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.diagnostics.txt
new file mode 100644
index 000000000000..4cc6f2d95400
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.diagnostics.txt
@@ -0,0 +1 @@
+x:\dir\subdir\Test\TestComponent.cshtml(1,59): Error RZ10001: The type of component 'Column' cannot be inferred based on the values provided. Consider specifying the type arguments directly using the following attributes: 'TItem'.
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.ir.txt
new file mode 100644
index 000000000000..f0940144f2b1
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.ir.txt
@@ -0,0 +1,27 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [75] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (58:0,58 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentTypeArgument - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
+ LazyIntermediateToken - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime
+ ComponentAttribute - (30:0,30 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (31:0,31 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_0
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.mappings.txt
new file mode 100644
index 000000000000..a30a4b4e995c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_NotCascaded/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime|
+Generated Location: (892:25,13 [8] )
+|DateTime|
+
+Source Location: (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (1214:34,32 [23] )
+|Array.Empty()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.codegen.cs
new file mode 100644
index 000000000000..84c684ee84ea
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.codegen.cs
@@ -0,0 +1,74 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ __o = typeof(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __o = Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck>(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __builder.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
+ __o = typeof(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ System.TimeZoneInfo
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __builder2.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder3) => {
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.ir.txt
new file mode 100644
index 000000000000..9e59831fb545
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.ir.txt
@@ -0,0 +1,26 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [103] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (58:0,58 [38] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentTypeArgument - (73:0,73 [19] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
+ LazyIntermediateToken - (73:0,73 [19] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - System.TimeZoneInfo
+ ComponentTypeArgument - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - TItem
+ LazyIntermediateToken - (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime
+ ComponentAttribute - (30:0,30 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (31:0,31 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.mappings.txt
new file mode 100644
index 000000000000..135b1cef10e4
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_Explicit_OverrideCascade/TestComponent.mappings.txt
@@ -0,0 +1,15 @@
+Source Location: (13:0,13 [8] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime|
+Generated Location: (892:25,13 [8] )
+|DateTime|
+
+Source Location: (32:0,32 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (1214:34,32 [23] )
+|Array.Empty()|
+
+Source Location: (73:0,73 [19] x:\dir\subdir\Test\TestComponent.cshtml)
+|System.TimeZoneInfo|
+Generated Location: (1602:44,73 [19] )
+|System.TimeZoneInfo|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.codegen.cs
new file mode 100644
index 000000000000..dd8ca884a9c0
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.codegen.cs
@@ -0,0 +1,93 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, __typeInferenceArg_0___arg0);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_2(__builder2, -1, __typeInferenceArg_0___arg0);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ public static void CreateColumn_2(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.ir.txt
new file mode 100644
index 000000000000..7df1eb01c61b
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.ir.txt
@@ -0,0 +1,28 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [68] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ Component - (51:0,51 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_2
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.mappings.txt
new file mode 100644
index 000000000000..da146c73342d
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded/TestComponent.mappings.txt
@@ -0,0 +1,5 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (973:26,15 [23] )
+|Array.Empty()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.codegen.cs
new file mode 100644
index 000000000000..83cb13c3e94d
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.codegen.cs
@@ -0,0 +1,113 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateParentOne_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ int.MaxValue
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateParentOne_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateParentTwo_1_CaptureParameters(
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+ "Hello"
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_1___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateParentTwo_1(__builder2, -1, -1, __typeInferenceArg_1___arg0, -1, (__builder3) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateChild_2(__builder3, -1, __typeInferenceArg_0___arg0, __typeInferenceArg_1___arg0);
+#nullable restore
+#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Child<,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(ParentTwo<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(ParentOne<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateParentOne_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TOne __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Value", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateParentOne_0_CaptureParameters(TOne __arg0, out TOne __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateParentTwo_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TTwo __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Value", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateParentTwo_1_CaptureParameters(TTwo __arg0, out TTwo __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateChild_2(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TOne __syntheticArg0, TTwo __syntheticArg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.ir.txt
new file mode 100644
index 000000000000..08650b3193c2
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.ir.txt
@@ -0,0 +1,40 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [120] x:\dir\subdir\Test\TestComponent.cshtml) - ParentOne
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (33:0,33 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (33:0,33 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (39:1,4 [67] x:\dir\subdir\Test\TestComponent.cshtml) - ParentTwo
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (69:1,34 [10] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (69:1,34 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (79:2,8 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Child
+ HtmlContent - (88:2,17 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (88:2,17 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ ComponentAttribute - (57:1,22 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value - AttributeStructure.DoubleQuotes
+ CSharpExpression - (58:1,23 [9] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (59:1,24 [7] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "Hello"
+ HtmlContent - (106:3,16 [2] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (106:3,16 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ ComponentAttribute - (18:0,18 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Value - Value - AttributeStructure.DoubleQuotes
+ CSharpExpression - (19:0,19 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (19:0,19 [12] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - int.MaxValue
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateParentOne_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateParentTwo_1
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateChild_2
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.mappings.txt
new file mode 100644
index 000000000000..4aae2caa3cc7
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedCombiningMultipleAncestors/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (19:0,19 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+|int.MaxValue|
+Generated Location: (982:26,19 [12] )
+|int.MaxValue|
+
+Source Location: (59:1,24 [7] x:\dir\subdir\Test\TestComponent.cshtml)
+|"Hello"|
+Generated Location: (1471:37,24 [7] )
+|"Hello"|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.codegen.cs
new file mode 100644
index 000000000000..38238e1d2e0b
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.codegen.cs
@@ -0,0 +1,90 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, __typeInferenceArg_0___arg0, -1, (context) => (__builder3) => {
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ __o = context.Year;
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0, int __seq0, global::Microsoft.AspNetCore.Components.RenderFragment __arg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "ChildContent", __arg0);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.ir.txt
new file mode 100644
index 000000000000..e69733b0cf6b
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.ir.txt
@@ -0,0 +1,29 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [78] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [30] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentChildContent - - ChildContent - context
+ CSharpExpression - (50:0,50 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (50:0,50 [12] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - context.Year
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.mappings.txt
new file mode 100644
index 000000000000..a36b677d8bb4
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithGenericChildContent/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (973:26,15 [23] )
+|Array.Empty()|
+
+Source Location: (50:0,50 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+|context.Year|
+Generated Location: (1525:36,50 [12] )
+|context.Year|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.codegen.cs
new file mode 100644
index 000000000000..8f22f7e48ce6
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.codegen.cs
@@ -0,0 +1,89 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, __typeInferenceArg_0___arg0, -1,
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ x => x.Year
+
+#line default
+#line hidden
+#nullable disable
+ );
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0, int __seq0, global::System.Func __arg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "SomeLambda", __arg0);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.ir.txt
new file mode 100644
index 000000000000..8533db30998f
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.ir.txt
@@ -0,0 +1,29 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [86] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [38] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentAttribute - (61:0,61 [14] x:\dir\subdir\Test\TestComponent.cshtml) - SomeLambda - SomeLambda - AttributeStructure.DoubleQuotes
+ CSharpExpression - (62:0,62 [13] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (63:0,63 [11] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x => x.Year
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.mappings.txt
new file mode 100644
index 000000000000..b4b3a47047a0
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithLambda/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (973:26,15 [23] )
+|Array.Empty()|
+
+Source Location: (63:0,63 [11] x:\dir\subdir\Test\TestComponent.cshtml)
+|x => x.Year|
+Generated Location: (1508:36,63 [11] )
+|x => x.Year|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.codegen.cs
new file mode 100644
index 000000000000..d0ad4c33c648
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.codegen.cs
@@ -0,0 +1,99 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateParent_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ new System.Collections.Generic.Dictionary()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0,
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime.MinValue
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg1);
+ __Blazor.Test.TestComponent.TypeInference.CreateParent_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, __typeInferenceArg_0___arg1, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateChild_1(__builder2, -1, __typeInferenceArg_0___arg1, __typeInferenceArg_0___arg0, __typeInferenceArg_0___arg0, -1,
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+ new[] { 'a', 'b', 'c' }
+
+#line default
+#line hidden
+#nullable disable
+ );
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Child<,,,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Parent<,,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateParent_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.Dictionary __arg0, int __seq1, TOther __arg1, int __seq2, global::Microsoft.AspNetCore.Components.RenderFragment __arg2)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Data", __arg0);
+ __builder.AddAttribute(__seq1, "Other", __arg1);
+ __builder.AddAttribute(__seq2, "ChildContent", __arg2);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateParent_0_CaptureParameters(global::System.Collections.Generic.Dictionary __arg0, out global::System.Collections.Generic.Dictionary __arg0_out, TOther __arg1, out TOther __arg1_out)
+ {
+ __arg0_out = __arg0;
+ __arg1_out = __arg1;
+ }
+ public static void CreateChild_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TOther __syntheticArg0, System.Collections.Generic.Dictionary __syntheticArg1, System.Collections.Generic.Dictionary __syntheticArg2, int __seq0, global::System.Collections.Generic.ICollection __arg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "ChildOnlyItems", __arg0);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.ir.txt
new file mode 100644
index 000000000000..d8888c31748c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.ir.txt
@@ -0,0 +1,36 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [172] x:\dir\subdir\Test\TestComponent.cshtml) - Parent
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (102:0,102 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (102:0,102 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (108:1,4 [53] x:\dir\subdir\Test\TestComponent.cshtml) - Child
+ ComponentAttribute - (131:1,27 [26] x:\dir\subdir\Test\TestComponent.cshtml) - ChildOnlyItems - ChildOnlyItems - AttributeStructure.DoubleQuotes
+ CSharpExpression - (132:1,28 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (133:1,29 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - new[] { 'a', 'b', 'c' }
+ HtmlContent - (161:1,57 [2] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (161:1,57 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ ComponentAttribute - (14:0,14 [59] x:\dir\subdir\Test\TestComponent.cshtml) - Data - Data - AttributeStructure.DoubleQuotes
+ CSharpExpression - (15:0,15 [58] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (16:0,16 [56] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - new System.Collections.Generic.Dictionary()
+ ComponentAttribute - (82:0,82 [18] x:\dir\subdir\Test\TestComponent.cshtml) - Other - Other - AttributeStructure.DoubleQuotes
+ CSharpExpression - (83:0,83 [17] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (83:0,83 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime.MinValue
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateParent_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateChild_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.mappings.txt
new file mode 100644
index 000000000000..dec291a8c6fb
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithMultipleTypes/TestComponent.mappings.txt
@@ -0,0 +1,15 @@
+Source Location: (16:0,16 [56] x:\dir\subdir\Test\TestComponent.cshtml)
+|new System.Collections.Generic.Dictionary()|
+Generated Location: (976:26,16 [56] )
+|new System.Collections.Generic.Dictionary()|
+
+Source Location: (83:0,83 [17] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime.MinValue|
+Generated Location: (1294:34,83 [17] )
+|DateTime.MinValue|
+
+Source Location: (133:1,29 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|new[] { 'a', 'b', 'c' }|
+Generated Location: (1881:44,29 [23] )
+|new[] { 'a', 'b', 'c' }|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.codegen.cs
new file mode 100644
index 000000000000..b13fdf7c5d0a
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.codegen.cs
@@ -0,0 +1,80 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ new Dictionary()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.Dictionary __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.Dictionary __arg0, out global::System.Collections.Generic.Dictionary __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.diagnostics.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.diagnostics.txt
new file mode 100644
index 000000000000..76e929cb8508
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.diagnostics.txt
@@ -0,0 +1 @@
+x:\dir\subdir\Test\TestComponent.cshtml(1,48): Error RZ10001: The type of component 'Column' cannot be inferred based on the values provided. Consider specifying the type arguments directly using the following attributes: 'TItem'.
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.ir.txt
new file mode 100644
index 000000000000..7a277bdf9a0d
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.ir.txt
@@ -0,0 +1,26 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [64] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (47:0,47 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentAttribute - (13:0,13 [32] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [31] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [29] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - new Dictionary()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.mappings.txt
new file mode 100644
index 000000000000..b2982ad218a7
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_CascadedWithUnrelatedGenericType_CreatesDiagnostic/TestComponent.mappings.txt
@@ -0,0 +1,5 @@
+Source Location: (15:0,15 [29] x:\dir\subdir\Test\TestComponent.cshtml)
+|new Dictionary()|
+Generated Location: (973:26,15 [29] )
+|new Dictionary()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.codegen.cs
new file mode 100644
index 000000000000..74dc1f7fb060
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.codegen.cs
@@ -0,0 +1,86 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __o = typeof(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ long
+
+#line default
+#line hidden
+#nullable disable
+ );
+ __builder2.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder3) => {
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<,>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.diagnostics.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.diagnostics.txt
new file mode 100644
index 000000000000..46ca91a9f7fa
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.diagnostics.txt
@@ -0,0 +1 @@
+x:\dir\subdir\Test\TestComponent.cshtml(1,42): Error RZ10000: The component 'Column' is missing required type arguments. Specify the missing types using the attributes: 'TItem'.
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.ir.txt
new file mode 100644
index 000000000000..baf9a093e4a6
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.ir.txt
@@ -0,0 +1,27 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [77] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [29] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentTypeArgument - (62:0,62 [4] x:\dir\subdir\Test\TestComponent.cshtml) - TChildOther
+ LazyIntermediateToken - (62:0,62 [4] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - long
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.mappings.txt
new file mode 100644
index 000000000000..5eaf9ca849eb
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_PartialCreatesDiagnostic/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (973:26,15 [23] )
+|Array.Empty()|
+
+Source Location: (62:0,62 [4] x:\dir\subdir\Test\TestComponent.cshtml)
+|long|
+Generated Location: (1414:36,62 [4] )
+|long|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.codegen.cs
new file mode 100644
index 000000000000..00bf2f16844c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.codegen.cs
@@ -0,0 +1,115 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ var parentKey = new object(); var childKey = new object();
+
+#line default
+#line hidden
+#nullable disable
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, __typeInferenceArg_0___arg0, -1, "", -1,
+#nullable restore
+#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime.MinValue
+
+#line default
+#line hidden
+#nullable disable
+ , -1,
+#nullable restore
+#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
+ childKey
+
+#line default
+#line hidden
+#nullable disable
+ );
+#nullable restore
+#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ , -1,
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+ parentKey
+
+#line default
+#line hidden
+#nullable disable
+ );
+ }
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1, int __seq2, object __arg2)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.SetKey(__arg2);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0, int __seq0, System.Object __arg0, int __seq1, System.Object __arg1, int __seq2, object __arg2)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Title", __arg0);
+ __builder.AddAttribute(__seq1, "Another", __arg1);
+ __builder.SetKey(__arg2);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.ir.txt
new file mode 100644
index 000000000000..ecb135c9a77c
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.ir.txt
@@ -0,0 +1,40 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ CSharpCode - (2:0,2 [60] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (2:0,2 [60] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - var parentKey = new object(); var childKey = new object();
+ Component - (65:1,0 [144] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (124:1,59 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (124:1,59 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (130:2,4 [70] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ SetKey - (145:2,19 [8] x:\dir\subdir\Test\TestComponent.cshtml) - childKey
+ ComponentAttribute - - Title - - AttributeStructure.DoubleQuotes
+ HtmlContent - (162:2,36 [5] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (162:2,36 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - Hello
+ ComponentAttribute - - Another - - AttributeStructure.DoubleQuotes
+ CSharpExpression - (178:2,52 [18] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (179:2,53 [17] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime.MinValue
+ HtmlContent - (200:2,74 [2] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (200:2,74 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ SetKey - (78:1,13 [9] x:\dir\subdir\Test\TestComponent.cshtml) - parentKey
+ ComponentAttribute - (96:1,31 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (97:1,32 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (98:1,33 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.mappings.txt
new file mode 100644
index 000000000000..157302ddbd60
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_Cascaded_WithSplatAndKey/TestComponent.mappings.txt
@@ -0,0 +1,25 @@
+Source Location: (2:0,2 [60] x:\dir\subdir\Test\TestComponent.cshtml)
+| var parentKey = new object(); var childKey = new object(); |
+Generated Location: (854:24,2 [60] )
+| var parentKey = new object(); var childKey = new object(); |
+
+Source Location: (98:1,33 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (1175:33,33 [23] )
+|Array.Empty()|
+
+Source Location: (179:2,53 [17] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime.MinValue|
+Generated Location: (1708:43,53 [17] )
+|DateTime.MinValue|
+
+Source Location: (145:2,19 [8] x:\dir\subdir\Test\TestComponent.cshtml)
+|childKey|
+Generated Location: (1894:51,19 [8] )
+|childKey|
+
+Source Location: (78:1,13 [9] x:\dir\subdir\Test\TestComponent.cshtml)
+|parentKey|
+Generated Location: (2249:68,13 [9] )
+|parentKey|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.codegen.cs
new file mode 100644
index 000000000000..5ec540f8ba19
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.codegen.cs
@@ -0,0 +1,90 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateAncestor_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateAncestor_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __builder2.AddAttribute(-1, "ChildContent", (Microsoft.AspNetCore.Components.RenderFragment)((__builder3) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateChild_1(__builder3, -1, __typeInferenceArg_0___arg0);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Child<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ ));
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Passthrough);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Ancestor<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateAncestor_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateAncestor_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateChild_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, System.Collections.Generic.IEnumerable __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.ir.txt
new file mode 100644
index 000000000000..2a48ff4eba75
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.ir.txt
@@ -0,0 +1,28 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [92] x:\dir\subdir\Test\TestComponent.cshtml) - Ancestor
+ ComponentChildContent - - ChildContent - context
+ Component - (45:0,45 [36] x:\dir\subdir\Test\TestComponent.cshtml) - Passthrough
+ ComponentChildContent - - ChildContent - context
+ Component - (58:0,58 [9] x:\dir\subdir\Test\TestComponent.cshtml) - Child
+ ComponentAttribute - (17:0,17 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (18:0,18 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (19:0,19 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateAncestor_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateChild_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.mappings.txt
new file mode 100644
index 000000000000..4a77428597c2
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerCascaded/TestComponent.mappings.txt
@@ -0,0 +1,5 @@
+Source Location: (19:0,19 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (981:26,19 [23] )
+|Array.Empty()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.codegen.cs
new file mode 100644
index 000000000000..0a58b511a097
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.codegen.cs
@@ -0,0 +1,166 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ DateTime.Now
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_1_CaptureParameters(
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+ System.Threading.Thread.CurrentThread
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_1___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_1(__builder2, -1, -1, __typeInferenceArg_1___arg0, -1, (__builder3) => {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_2_CaptureParameters(__typeInferenceArg_1___arg0, out var __typeInferenceArg_2___syntheticArg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_2(__builder3, -1, __typeInferenceArg_2___syntheticArg0, -1, (__builder4) => {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_3_CaptureParameters(__typeInferenceArg_1___arg0, out var __typeInferenceArg_3___syntheticArg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_3(__builder4, -1, __typeInferenceArg_3___syntheticArg0);
+ }
+#nullable restore
+#line 4 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(TreeNode<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(TreeNode<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(TreeNode<>);
+
+#line default
+#line hidden
+#nullable disable
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_4_CaptureParameters(__typeInferenceArg_0___arg0, out var __typeInferenceArg_1___syntheticArg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateTreeNode_4(__builder2, -1, __typeInferenceArg_1___syntheticArg0);
+ }
+#nullable restore
+#line 7 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(TreeNode<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(TreeNode<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateTreeNode_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TItem __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Item", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateTreeNode_0_CaptureParameters(TItem __arg0, out TItem __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateTreeNode_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TItem __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Item", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateTreeNode_1_CaptureParameters(TItem __arg0, out TItem __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateTreeNode_2(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TItem __syntheticArg0, int __seq0, global::Microsoft.AspNetCore.Components.RenderFragment __arg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "ChildContent", __arg0);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateTreeNode_2_CaptureParameters(TItem __syntheticArg0, out TItem __syntheticArg0_out)
+ {
+ __syntheticArg0_out = __syntheticArg0;
+ }
+ public static void CreateTreeNode_3(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TItem __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateTreeNode_3_CaptureParameters(TItem __syntheticArg0, out TItem __syntheticArg0_out)
+ {
+ __syntheticArg0_out = __syntheticArg0;
+ }
+ public static void CreateTreeNode_4(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, TItem __syntheticArg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateTreeNode_4_CaptureParameters(TItem __syntheticArg0, out TItem __syntheticArg0_out)
+ {
+ __syntheticArg0_out = __syntheticArg0;
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.ir.txt
new file mode 100644
index 000000000000..cb6d9cd456c6
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.ir.txt
@@ -0,0 +1,51 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [208] x:\dir\subdir\Test\TestComponent.cshtml) - TreeNode
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (31:0,31 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (31:0,31 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (37:1,4 [140] x:\dir\subdir\Test\TestComponent.cshtml) - TreeNode
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (93:1,60 [10] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (93:1,60 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (103:2,8 [57] x:\dir\subdir\Test\TestComponent.cshtml) - TreeNode
+ ComponentChildContent - - ChildContent - context
+ HtmlContent - (113:2,18 [14] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (113:2,18 [14] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (127:3,12 [12] x:\dir\subdir\Test\TestComponent.cshtml) - TreeNode
+ HtmlContent - (139:3,24 [10] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (139:3,24 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ HtmlContent - (160:4,19 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (160:4,19 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ ComponentAttribute - (53:1,20 [38] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item - AttributeStructure.DoubleQuotes
+ CSharpExpression - (54:1,21 [37] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (54:1,21 [37] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - System.Threading.Thread.CurrentThread
+ HtmlContent - (177:5,15 [6] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (177:5,15 [6] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ Component - (183:6,4 [12] x:\dir\subdir\Test\TestComponent.cshtml) - TreeNode
+ HtmlContent - (195:6,16 [2] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (195:6,16 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
+ ComponentAttribute - (16:0,16 [13] x:\dir\subdir\Test\TestComponent.cshtml) - Item - Item - AttributeStructure.DoubleQuotes
+ CSharpExpression - (17:0,17 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (17:0,17 [12] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - DateTime.Now
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateTreeNode_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateTreeNode_1
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateTreeNode_2
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateTreeNode_3
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateTreeNode_4
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.mappings.txt
new file mode 100644
index 000000000000..779de1587264
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_MultiLayerOverrideCascade/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (17:0,17 [12] x:\dir\subdir\Test\TestComponent.cshtml)
+|DateTime.Now|
+Generated Location: (979:26,17 [12] )
+|DateTime.Now|
+
+Source Location: (54:1,21 [37] x:\dir\subdir\Test\TestComponent.cshtml)
+|System.Threading.Thread.CurrentThread|
+Generated Location: (1463:37,21 [37] )
+|System.Threading.Thread.CurrentThread|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.codegen.cs
new file mode 100644
index 000000000000..5611c44985e3
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.codegen.cs
@@ -0,0 +1,72 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1,
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1);
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.diagnostics.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.diagnostics.txt
new file mode 100644
index 000000000000..060bab8b698a
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.diagnostics.txt
@@ -0,0 +1 @@
+x:\dir\subdir\Test\TestComponent.cshtml(1,42): Error RZ10001: The type of component 'Column' cannot be inferred based on the values provided. Consider specifying the type arguments directly using the following attributes: 'TItem'.
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.ir.txt
new file mode 100644
index 000000000000..6f60398e43ce
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.ir.txt
@@ -0,0 +1,26 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [58] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [10] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.mappings.txt
new file mode 100644
index 000000000000..1a74df4e3c82
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_NotCascaded/TestComponent.mappings.txt
@@ -0,0 +1,5 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty()|
+Generated Location: (955:25,15 [23] )
+|Array.Empty()|
+
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.codegen.cs b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.codegen.cs
new file mode 100644
index 000000000000..03c2ca8f9738
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.codegen.cs
@@ -0,0 +1,89 @@
+//
+#pragma warning disable 1591
+namespace Test
+{
+ #line hidden
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using Microsoft.AspNetCore.Components;
+ public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
+ {
+ #pragma warning disable 219
+ private void __RazorDirectiveTokenHelpers__() {
+ }
+ #pragma warning restore 219
+ #pragma warning disable 0414
+ private static System.Object __o = null;
+ #pragma warning restore 0414
+ #pragma warning disable 1998
+ protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
+ {
+ {
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0_CaptureParameters(
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ Array.Empty()
+
+#line default
+#line hidden
+#nullable disable
+ , out var __typeInferenceArg_0___arg0);
+ __Blazor.Test.TestComponent.TypeInference.CreateGrid_0(__builder, -1, -1, __typeInferenceArg_0___arg0, -1, (__builder2) => {
+ __Blazor.Test.TestComponent.TypeInference.CreateColumn_1(__builder2, -1, -1,
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+ "Some string"
+
+#line default
+#line hidden
+#nullable disable
+ );
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Column<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ );
+ }
+#nullable restore
+#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
+__o = typeof(Grid<>);
+
+#line default
+#line hidden
+#nullable disable
+ }
+ #pragma warning restore 1998
+ }
+}
+namespace __Blazor.Test.TestComponent
+{
+ #line hidden
+ internal static class TypeInference
+ {
+ public static void CreateGrid_0(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, global::System.Collections.Generic.IEnumerable __arg0, int __seq1, global::Microsoft.AspNetCore.Components.RenderFragment __arg1)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "Items", __arg0);
+ __builder.AddAttribute(__seq1, "ChildContent", __arg1);
+ __builder.CloseComponent();
+ }
+
+ public static void CreateGrid_0_CaptureParameters(global::System.Collections.Generic.IEnumerable __arg0, out global::System.Collections.Generic.IEnumerable __arg0_out)
+ {
+ __arg0_out = __arg0;
+ }
+ public static void CreateColumn_1(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder, int seq, int __seq0, TItem __arg0)
+ {
+ __builder.OpenComponent>(seq);
+ __builder.AddAttribute(__seq0, "OverrideParam", __arg0);
+ __builder.CloseComponent();
+ }
+ }
+}
+#pragma warning restore 1591
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.ir.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.ir.txt
new file mode 100644
index 000000000000..a6df49236579
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.ir.txt
@@ -0,0 +1,29 @@
+Document -
+ NamespaceDeclaration - - Test
+ UsingDirective - (3:1,1 [12] ) - System
+ UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
+ UsingDirective - (53:3,1 [17] ) - System.Linq
+ UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
+ UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
+ ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
+ DesignTimeDirective -
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning disable 0414
+ CSharpCode -
+ IntermediateToken - - CSharp - private static System.Object __o = null;
+ CSharpCode -
+ IntermediateToken - - CSharp - #pragma warning restore 0414
+ MethodDeclaration - - protected override - void - BuildRenderTree
+ Component - (0:0,0 [91] x:\dir\subdir\Test\TestComponent.cshtml) - Grid
+ ComponentChildContent - - ChildContent - context
+ Component - (41:0,41 [43] x:\dir\subdir\Test\TestComponent.cshtml) - Column
+ ComponentAttribute - (64:0,64 [16] x:\dir\subdir\Test\TestComponent.cshtml) - OverrideParam - OverrideParam - AttributeStructure.DoubleQuotes
+ CSharpExpression - (65:0,65 [15] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (66:0,66 [13] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "Some string"
+ ComponentAttribute - (13:0,13 [26] x:\dir\subdir\Test\TestComponent.cshtml) - Items - Items - AttributeStructure.DoubleQuotes
+ CSharpExpression - (14:0,14 [25] x:\dir\subdir\Test\TestComponent.cshtml)
+ LazyIntermediateToken - (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - Array.Empty()
+ NamespaceDeclaration - - __Blazor.Test.TestComponent
+ ClassDeclaration - - internal static - TypeInference - -
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateGrid_0
+ ComponentTypeInferenceMethod - - __Blazor.Test.TestComponent.TypeInference - CreateColumn_1
diff --git a/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.mappings.txt b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.mappings.txt
new file mode 100644
index 000000000000..7945d18cb125
--- /dev/null
+++ b/src/Razor/Microsoft.AspNetCore.Razor.Language/test/TestFiles/IntegrationTests/ComponentDesignTimeCodeGenerationTest/ChildComponent_Generic_TypeInference_OverrideCascade/TestComponent.mappings.txt
@@ -0,0 +1,10 @@
+Source Location: (15:0,15 [23] x:\dir\subdir\Test\TestComponent.cshtml)
+|Array.Empty