diff --git a/src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.Function.cs b/src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.Function.cs index e26efc73..9ffec637 100644 --- a/src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.Function.cs +++ b/src/PolyType.SourceGenerator/SourceFormatter/SourceFormatter.Function.cs @@ -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}")); string argumentStateCtorExpr = functionShapeModel.Parameters switch { @@ -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 ? "!" : ""; } diff --git a/tests/PolyType.SourceGenerator.UnitTests/CompilationTests.FunctionShapes.cs b/tests/PolyType.SourceGenerator.UnitTests/CompilationTests.FunctionShapes.cs index 7a26a970..86b7dc93 100644 --- a/tests/PolyType.SourceGenerator.UnitTests/CompilationTests.FunctionShapes.cs +++ b/tests/PolyType.SourceGenerator.UnitTests/CompilationTests.FunctionShapes.cs @@ -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() {