First of all, thank you for an awesome mapper! Keep up the good work ๐
Describe the bug
warning CS8785: Generator 'MapperGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'An item with the same key has already been added.
Iโll try to explain, but its maybe easier to fire up the debugger yourselves with this repo, as the bug is a bit complex.
The code flow ends up trying to add (string, string)
twice to the mappers dictionary.
First it adds the mapping (string, string)
correctly.
Then, trying to add mapping between the List<string>
, since the target dto is flagged #nullable disable
, it correctly calls FindOrBuildMapping(string, string?)
This method again runs the FindMapping(string, string?)
, and correctly returns that there are no existing mappings for (string, string?)
.
Then the BuildDelegateMapping(null, string, string?)
method runs, and results in the NullableMappingBuilder
returns here:
|
// if only the target is nullable and is not a nullable value type |
|
// no conversion / null handling is needed at all. |
|
if (!sourceIsNullable && targetIsNullable && !ctx.Target.IsNullableValueType()) |
|
return ctx.BuildDelegateMapping(ctx.Source, targetNonNullable!); |
This changes the mapping to (string, string)
. There is not any new check if this mapping already exists, and the _mappings.Add()
throws the exception.
To Reproduce
Build this repo: https://github.com/stigrune/BugReport.Mapperly
Look at build output.
Code snippets
Added personal comments to the code from DescriptorBuilder.cs
public TypeMapping? FindOrBuildMapping(
ITypeSymbol sourceType,
ITypeSymbol targetType)
{
// (string, string?) here, and it does not exists.
if (FindMapping(sourceType, targetType) is { } foundMapping)
return foundMapping;
// Inside the BuildDelegateMapping, NullableMappingBuilder ends up changing the target from string? to string.
if (BuildDelegateMapping(null, sourceType, targetType) is not { } mapping)
return null;
// mapping is (string, string) here, and this already exists.
AddMapping(mapping);
return mapping;
}
Environment (please complete the following information):
- Mapperly Version: 2.3.1
- .NET Version: 6.0.302
- Target Framework: net6.0
- OS: Windows
A quick obvious fix is to recheck if the mapping exists just before trying to add it to the dictionary. This might be the best way to fix it if other MappingBuilders also modify the source or targets?
Reply with a description of the desired fix, and I'll happily try to help out and submit a PR ๐
Edit: Fixed typo and mix-up between what is source and target types.