dotnet/runtime

Logging Source Generator fails to compile when `in` parameter modifier is present

gfoidl opened this issue · 2 comments

Description

The logging source generator drops the in modifier, so the project fails to compile.

See repro below for code, but essential is:

[LoggerMessage(2, LogLevel.Information, "Foo: {my}")]
public static partial void LogSomething1(this ILogger logger, in MyReadOnlyStruct my);

The generated code

[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.5.2210")]
public static partial void LogSomething1(this global::Microsoft.Extensions.Logging.ILogger logger, global::MyReadOnlyStruct my)
{
    if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Information))
    {
        __LogSomething1Callback(logger, my, null);
    }
}

doesn't have the in parameter modifier, so this defined method can't be found --> compilation fails.

For completeness: the same occurs when ref modifier is used.

Reproduction Steps

using Microsoft.Extensions.Logging;

ILogger logger      = null!;    // will fail at runtime, but to keep the repro simple...
MyReadOnlyStruct my = new(3, 4, 5, 6);

logger.LogSomething(my);
logger.LogSomething1(my);

public static partial class LogExtensions
{
    // This works as expected.
    [LoggerMessage(1, LogLevel.Information, "Foo: {my}")]
    public static partial void LogSomething(this ILogger logger, MyReadOnlyStruct my);

    // This fails, as no defining declaration with the correct overload can be found.
    [LoggerMessage(2, LogLevel.Information, "Foo: {my}")]
    public static partial void LogSomething1(this ILogger logger, in MyReadOnlyStruct my);
}

public readonly record struct MyReadOnlyStruct(double X, double Y, double Z, double W);

Expected behavior

Build succeeds -- the correct definition of the method is generated, so Roslyn can bind to that method.

Actual behavior

Build fails.

1>D:\...\ConsoleApp3\Program.cs(17,32,17,45): error CS8795: Partial method 'LogExtensions.LogSomething1(ILogger, in MyReadOnlyStruct)' must have an implementation part because it has accessibility modifiers.
1>D:\...\ConsoleApp3\Microsoft.Extensions.Logging.Generators\Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator\LoggerMessage.g.cs(23,36,23,49): error CS0759: No defining declaration found for implementing declaration of partial method 'LogExtensions.LogSomething1(ILogger, MyReadOnlyStruct)'
1>Done building project "ConsoleApp3.csproj" -- FAILED.

Regression?

No.

Known Workarounds

Don't use in or ref.

Configuration

.NET SDK 6.0.100

Other information

No response

Tagging subscribers to this area: @dotnet/area-extensions-logging
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

The logging source generator drops the in modifier, so the project fails to compile.

See repro below for code, but essential is:

[LoggerMessage(2, LogLevel.Information, "Foo: {my}")]
public static partial void LogSomething1(this ILogger logger, in MyReadOnlyStruct my);

The generated code

[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.5.2210")]
public static partial void LogSomething1(this global::Microsoft.Extensions.Logging.ILogger logger, global::MyReadOnlyStruct my)
{
    if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Information))
    {
        __LogSomething1Callback(logger, my, null);
    }
}

doesn't have the in parameter modifier, so this defined method can't be found --> compilation fails.

For completeness: the same occurs when ref modifier is used.

Reproduction Steps

using Microsoft.Extensions.Logging;

ILogger logger      = null!;    // will fail at runtime, but to keep the repro simple...
MyReadOnlyStruct my = new(3, 4, 5, 6);

logger.LogSomething(my);
logger.LogSomething1(my);

public static partial class LogExtensions
{
    // This works as expected.
    [LoggerMessage(1, LogLevel.Information, "Foo: {my}")]
    public static partial void LogSomething(this ILogger logger, MyReadOnlyStruct my);

    // This fails, as no defining declaration with the correct overload can be found.
    [LoggerMessage(2, LogLevel.Information, "Foo: {my}")]
    public static partial void LogSomething1(this ILogger logger, in MyReadOnlyStruct my);
}

public readonly record struct MyReadOnlyStruct(double X, double Y, double Z, double W);

Expected behavior

Build succeeds -- the correct definition of the method is generated, so Roslyn can bind to that method.

Actual behavior

Build fails.

1>D:\...\ConsoleApp3\Program.cs(17,32,17,45): error CS8795: Partial method 'LogExtensions.LogSomething1(ILogger, in MyReadOnlyStruct)' must have an implementation part because it has accessibility modifiers.
1>D:\...\ConsoleApp3\Microsoft.Extensions.Logging.Generators\Microsoft.Extensions.Logging.Generators.LoggerMessageGenerator\LoggerMessage.g.cs(23,36,23,49): error CS0759: No defining declaration found for implementing declaration of partial method 'LogExtensions.LogSomething1(ILogger, MyReadOnlyStruct)'
1>Done building project "ConsoleApp3.csproj" -- FAILED.

Regression?

No.

Known Workarounds

Don't use in or ref.

Configuration

.NET SDK 6.0.100

Other information

No response

Author: gfoidl
Assignees: -
Labels:

untriaged, area-Extensions-Logging

Milestone: -

Fixed in #64593