Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid synthesizing incorrect allows ref struct delegate type parameters #74914

Merged
merged 1 commit into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal AnonymousDelegateTemplateSymbol(
Debug.Assert(refKinds.IsNull || parameterCount == refKinds.Capacity - (voidReturnTypeOpt is { } ? 0 : 1));

HasIndexedName = false;
TypeParameters = CreateTypeParameters(this, parameterCount, returnsVoid: voidReturnTypeOpt is { });
TypeParameters = CreateTypeParameters(this, parameterCount, returnsVoid: voidReturnTypeOpt is { }, hasParamsArray: false);
NameAndIndex = new NameAndIndex(name, index: 0);

var constructor = new SynthesizedDelegateConstructor(this, objectType, intPtrType);
Expand Down Expand Up @@ -70,17 +70,20 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod(AnonymousDelegateTempl
}
}

private static ImmutableArray<TypeParameterSymbol> CreateTypeParameters(AnonymousDelegateTemplateSymbol containingType, int parameterCount, bool returnsVoid)
private static ImmutableArray<TypeParameterSymbol> CreateTypeParameters(AnonymousDelegateTemplateSymbol containingType, int parameterCount, bool returnsVoid, bool hasParamsArray)
Copy link
Member

Choose a reason for hiding this comment

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

Was trying to think of any other cases where this could be a problem but couldn't come up with anything. Was thinking through situations like

var del = int (ref int i) => 0;

That is fine though. There aren't restrictions to having ref to type parameters that allows ref struct.

{
var allowRefLikeTypes = containingType.ContainingAssembly.RuntimeSupportsByRefLikeGenerics;

var typeParameters = ArrayBuilder<TypeParameterSymbol>.GetInstance(parameterCount + (returnsVoid ? 0 : 1));
for (int i = 0; i < parameterCount; i++)
{
typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, i, "T" + (i + 1)));
typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, i, "T" + (i + 1),
allowsRefLikeType: allowRefLikeTypes && (!hasParamsArray || i != parameterCount - 1)));
}

if (!returnsVoid)
{
typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, parameterCount, "TResult"));
typeParameters.Add(new AnonymousTypeManager.AnonymousTypeParameterSymbol(containingType, parameterCount, "TResult", allowsRefLikeType: allowRefLikeTypes));
}

return typeParameters.ToImmutableAndFree();
Expand All @@ -103,7 +106,8 @@ internal AnonymousDelegateTemplateSymbol(AnonymousTypeManager manager, Anonymous
TypeParameters = CreateTypeParameters(
this,
parameterCount: typeDescr.Fields.Length - 1,
returnsVoid: typeDescr.Fields[^1].Type.IsVoidType());
returnsVoid: typeDescr.Fields[^1].Type.IsVoidType(),
hasParamsArray: typeDescr.Fields is [.., { IsParams: true }, _]);

var constructor = new SynthesizedDelegateConstructor(this, manager.System_Object, manager.System_IntPtr);
// https://github.com/dotnet/roslyn/issues/56808: Synthesized delegates should include BeginInvoke() and EndInvoke().
Expand Down Expand Up @@ -172,7 +176,8 @@ internal AnonymousDelegateTemplateSymbol(AnonymousTypeManager manager, Anonymous
var typeParameters = ArrayBuilder<TypeParameterSymbol>.GetInstance(typeParameterCount);
for (int i = 0; i < typeParameterCount; i++)
{
typeParameters.Add(new AnonymousTypeParameterSymbol(this, i, "T" + (i + 1)));
typeParameters.Add(new AnonymousTypeParameterSymbol(this, i, "T" + (i + 1),
allowsRefLikeType: typeParametersToSubstitute[i].AllowsRefLikeType));
}
TypeParameters = typeParameters.ToImmutableAndFree();
typeMap = new TypeMap(typeParametersToSubstitute, TypeParameters, allowAlpha: true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousType

// Add a type parameter
AnonymousTypeParameterSymbol typeParameter =
new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name));
new AnonymousTypeParameterSymbol(this, fieldIndex, GeneratedNames.MakeAnonymousTypeParameterName(field.Name), allowsRefLikeType: false);
typeParametersBuilder.Add(typeParameter);

// Add a property
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ internal sealed class AnonymousTypeParameterSymbol : TypeParameterSymbol
private readonly AnonymousTypeOrDelegateTemplateSymbol _container;
private readonly int _ordinal;
private readonly string _name;
private readonly bool _allowsRefLikeType;

public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol container, int ordinal, string name)
public AnonymousTypeParameterSymbol(AnonymousTypeOrDelegateTemplateSymbol container, int ordinal, string name, bool allowsRefLikeType)
{
Debug.Assert((object)container != null);
Debug.Assert(!string.IsNullOrEmpty(name));

_container = container;
_ordinal = ordinal;
_name = name;
_allowsRefLikeType = allowsRefLikeType;
}

public override TypeParameterKind TypeParameterKind
Expand Down Expand Up @@ -91,13 +93,7 @@ public override bool HasValueTypeConstraint
get { return false; }
}

public override bool AllowsRefLikeType
{
get
{
return _container.IsDelegateType() && ContainingAssembly.RuntimeSupportsByRefLikeGenerics;
}
}
public override bool AllowsRefLikeType => _allowsRefLikeType;

public override bool IsValueTypeFromConstraintTypes
{
Expand Down
Loading
Loading