Skip to content

Commit

Permalink
Add extract method support for ref struct interfaces (#73619)
Browse files Browse the repository at this point in the history
* Add extract method support for ref struct interfaces

The method extraction code uses ITypeParameterSymbol's constraints to generate the new method's text. This codepath had not yet been modified to support ITypeParameterSymbol.AllowsRefLikeType

This is in support of the "allows ref struct" on interfaces feature outlined here: #72124

This ref structs for interfaces feature was merged via this PR: #73567
  • Loading branch information
ToddGrun authored May 22, 2024
1 parent 1d8582e commit 45cb0c8
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,39 @@ class Program
await TestExtractMethodAsync(code, expected);
}

[Fact]
public async Task SelectTypeParameterWithAllowsRefStructAntiConstraint()
{
var code = """
using System;
class Program
{
void MyMethod1<TT>(TT tt) where TT : IDisposable, allows ref struct
{
[|tt.Dispose();|]
}
}
""";
var expected = """
using System;
class Program
{
void MyMethod1<TT>(TT tt) where TT : IDisposable, allows ref struct
{
NewMethod(tt);
}
private static void NewMethod<TT>(TT tt) where TT : IDisposable, allows ref struct
{
tt.Dispose();
}
}
""";

await TestExtractMethodAsync(code, expected);
}
[Fact]
public async Task SelectTypeParameter()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ protected ImmutableArray<ITypeParameterSymbol> CreateMethodTypeParameters()
typeParameters.Add(CodeGenerationSymbolFactory.CreateTypeParameter(
parameter.GetAttributes(), parameter.Variance, parameter.Name, [], parameter.NullableAnnotation,
parameter.HasConstructorConstraint, parameter.HasReferenceTypeConstraint, parameter.HasUnmanagedTypeConstraint,
parameter.HasValueTypeConstraint, parameter.HasNotNullConstraint, parameter.Ordinal));
parameter.HasValueTypeConstraint, parameter.HasNotNullConstraint, parameter.AllowsRefLikeType, parameter.Ordinal));
}

return typeParameters.ToImmutableAndFree();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ private static ImmutableArray<ITypeParameterSymbol> RenameTypeParameters(
typeParameter.HasValueTypeConstraint,
typeParameter.HasUnmanagedTypeConstraint,
typeParameter.HasNotNullConstraint,
typeParameter.AllowsRefLikeType,
typeParameter.Ordinal);

newTypeParameters.Add(newTypeParameter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ private static void AddConstraintClauses(
constraints.Add(ConstructorConstraint());
}

if (typeParameter.AllowsRefLikeType)
{
// "allows ref struct" anti-constraint must be last
constraints.Add(AllowsConstraintClause([RefStructConstraint()]));
}

if (constraints.Count == 0)
{
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ public static ITypeParameterSymbol CreateTypeParameterSymbol(string name, int or
attributes: default, varianceKind: VarianceKind.None,
name: name, constraintTypes: [],
hasConstructorConstraint: false, hasReferenceConstraint: false, hasValueConstraint: false,
hasUnmanagedConstraint: false, hasNotNullConstraint: false, ordinal: ordinal);
hasUnmanagedConstraint: false, hasNotNullConstraint: false, allowsRefLikeType: false,
ordinal: ordinal);
}

/// <summary>
Expand All @@ -338,9 +339,10 @@ public static ITypeParameterSymbol CreateTypeParameter(
bool hasUnmanagedConstraint = false,
bool hasValueConstraint = false,
bool hasNotNullConstraint = false,
bool allowsRefLikeType = false,
int ordinal = 0)
{
return new CodeGenerationTypeParameterSymbol(null, attributes, varianceKind, name, nullableAnnotation, constraintTypes, hasConstructorConstraint, hasReferenceConstraint, hasValueConstraint, hasUnmanagedConstraint, hasNotNullConstraint, ordinal);
return new CodeGenerationTypeParameterSymbol(null, attributes, varianceKind, name, nullableAnnotation, constraintTypes, hasConstructorConstraint, hasReferenceConstraint, hasValueConstraint, hasUnmanagedConstraint, hasNotNullConstraint, allowsRefLikeType, ordinal);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ internal class CodeGenerationTypeParameterSymbol(
bool hasValueConstraint,
bool hasUnmanagedConstraint,
bool hasNotNullConstraint,
bool allowsRefLikeType,
int ordinal) : CodeGenerationTypeSymbol(containingType?.ContainingAssembly, containingType, attributes, Accessibility.NotApplicable, default, name, SpecialType.None, nullableAnnotation), ITypeParameterSymbol
{
public VarianceKind Variance { get; } = varianceKind;
public ImmutableArray<ITypeSymbol> ConstraintTypes { get; internal set; } = constraintTypes;
public bool HasConstructorConstraint { get; } = hasConstructorConstraint;
public bool HasReferenceTypeConstraint { get; } = hasReferenceConstraint;
public bool HasValueTypeConstraint { get; } = hasValueConstraint;
public bool AllowsRefLikeType => false;
public bool AllowsRefLikeType { get; } = allowsRefLikeType;
public bool HasUnmanagedTypeConstraint { get; } = hasUnmanagedConstraint;
public bool HasNotNullConstraint { get; } = hasNotNullConstraint;
public int Ordinal { get; } = ordinal;
Expand All @@ -37,7 +38,8 @@ protected override CodeGenerationTypeSymbol CloneWithNullableAnnotation(Nullable
return new CodeGenerationTypeParameterSymbol(
this.ContainingType, this.GetAttributes(), this.Variance, this.Name, nullableAnnotation,
this.ConstraintTypes, this.HasConstructorConstraint, this.HasReferenceTypeConstraint,
this.HasValueTypeConstraint, this.HasUnmanagedTypeConstraint, this.HasNotNullConstraint, this.Ordinal);
this.HasValueTypeConstraint, this.HasUnmanagedTypeConstraint, this.HasNotNullConstraint,
this.AllowsRefLikeType, this.Ordinal);
}

public new ITypeParameterSymbol OriginalDefinition => this;
Expand Down

0 comments on commit 45cb0c8

Please sign in to comment.