Skip to content
Open
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 @@ -176,7 +176,7 @@ static string FormatFunctionParameterExpr(ParameterShapeModel parameter, bool is
}

string delegateSignature = string.Join(", ", functionShapeModel.Parameters
.Select(parameter => $"{FormatRefPrefix(parameter)}{parameter.ParameterType.FullyQualifiedName}{GetNullableSuffix(parameter)} {parameter.Name}"));
.Select(parameter => $"{FormatRefPrefix(parameter)}{FormatDelegateParameterType(parameter)} {parameter.Name}"));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Does the issue occur with constructor methods? I feel the underlying issue here is that nullable annotations isn't being stripped in delegate parameters, unlike what is happening with constructor or method shapes.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I do not understand. Is this a clarification question: "does this issue occur with constructor methods [too]"? If not I can only clarify: when using top-level statements, the delegate turns into a global non-Program-class owned delegate.

Ahh I think I understand what you mean. So you say, that nullable annotations are stripped for method parameters, but not for constructor parameters and method parameters.

I am not sure what you mean by "nullable annotation stripping". Am I right in the assumption, that you mean PolyType that does nullable annotation stripping?

I did not researched, how the nullable annotation (stripping) is handled by PolyType in case of constructor parameters or method parameters. If you want I can do that and report back.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

There are many parts of the source generator that deal with method/constructor parameter. I was asking if this is the only location where the bug manifests. What happens if the same pattern occurs in a constructor annotated with [ConstructorShape]?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks for clarification.. Sorry I have seen it.. my time.. I try to take a closer look this weekend. Sorry for the huge delay.


string argumentStateCtorExpr = functionShapeModel.Parameters switch
{
Expand All @@ -199,7 +199,19 @@ static string FormatFunctionParameterExpr(ParameterShapeModel parameter, bool is

return $$"""static {{innerFuncVar}} => ({{delegateSignature}}) => { {{functionArgumentStateFQN}} {{stateVar}} = {{argumentStateCtorExpr}}; {{tailExpr}}; }""";

static string GetNullableSuffix(ParameterShapeModel parameter) => parameter.NullableAnnotation is NullableAnnotation.Annotated ? "?" : "";
static string FormatDelegateParameterType(ParameterShapeModel parameter)
{
string parameterType = parameter.ParameterType.FullyQualifiedName;
if (parameter.NullableAnnotation is not NullableAnnotation.Annotated)
{
return parameterType;
}

return parameterType.Length > 0 && parameterType[^1] == '?'
? parameterType
: parameterType + "?";
}

static string GetSuppressionSuffix(ParameterShapeModel parameter) => parameter.ParameterTypeContainsNullabilityAnnotations ? "!" : "";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ public partial class Witness { }
Assert.Empty(result.Diagnostics);
}

[Fact]
public static void DelegateShapes_NullableBoolParameter_NoErrors()
{
// Regression test for nullable bool delegate parameters being emitted as bool??.
Compilation compilation = CompilationHelpers.CreateCompilation("""
using PolyType;

public delegate void BrokenCommand(bool? skipDuplicate = null);

[GenerateShapeFor(typeof(BrokenCommand))]
public partial class Witness { }
""");

PolyTypeSourceGeneratorResult result = CompilationHelpers.RunPolyTypeSourceGenerator(compilation);
Assert.Empty(result.Diagnostics);
}

[Fact]
public static void EventShapes_PublicInstanceAndStatic_NoErrors()
{
Expand Down