@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -251,7 +251,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return ;
// Two exact bounds that differ only in tuple element names are not conflicting;
// their names are merged instead (kept where both agree, dropped otherwise).
IType merged = MergeTupleNam es ( ExactBound , type ) ;
IType merged = MergeSimilarTyp es ( ExactBound , type ) ;
if ( merged ! = null )
ExactBound = merged ;
else
@ -987,7 +987,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -987,7 +987,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// MergeTupleNames in Roslyn's MethodTypeInference.cs.
IType fixedTo = tp . ExactBound ;
foreach ( var b in tp . LowerBounds . Concat ( tp . UpperBounds ) )
fixedTo = MergeTupleNam es ( fixedTo , b ) ? ? fixedTo ;
fixedTo = MergeSimilarTyp es ( fixedTo , b ) ? ? fixedTo ;
// the exact bound determines the result, up to the merged element names
tp . FixedTo = fixedTo ;
// check validity
@ -1018,11 +1018,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1018,11 +1018,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
/// <summary>
/// Merges the tuple element names of two types that are equal apart from those names:
/// a name is kept where both sides agree and dropped where they conflict. Returns
/// <c>null</c> if the types differ in anything else.
/// Merges similar types that differ only in tuple element names and/or object/dynamic, recursively.
/// * for tuple element names, a name is kept where both sides agree and dropped where they conflict.
/// * for object/dynamic, dynamic is preferred over object.
/// Returns <c>null</c> if the types differ in any other aspects.
/// </summary>
static IType MergeTupleNam es ( IType a , IType b )
static IType MergeSimilarTyp es ( IType a , IType b )
{
if ( a . Equals ( b ) )
return a ;
@ -1032,16 +1033,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1032,16 +1033,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return null ;
if ( a is NullabilityAnnotatedType na & & b is NullabilityAnnotatedType nb )
{
return MergeTupleNam es ( na . TypeWithoutAnnotation , nb . TypeWithoutAnnotation )
return MergeSimilarTyp es ( na . TypeWithoutAnnotation , nb . TypeWithoutAnnotation )
? . ChangeNullability ( a . Nullability ) ;
}
if ( a . Kind = = TypeKind . Dynamic & & b . IsKnownType ( KnownTypeCode . Object ) )
{
return a ;
}
if ( b . Kind = = TypeKind . Dynamic & & a . IsKnownType ( KnownTypeCode . Object ) )
{
return b ;
}
if ( a is TupleType ta & & b is TupleType tb
& & ta . ElementTypes . Length = = tb . ElementTypes . Length )
{
var mergedElements = ImmutableArray . CreateBuilder < IType > ( ta . ElementTypes . Length ) ;
for ( int i = 0 ; i < ta . ElementTypes . Length ; i + + )
{
var merged = MergeTupleNames ( ta . ElementTypes [ i ] , tb . ElementTypes [ i ] ) ;
var merged = MergeSimilarTyp es ( ta . ElementTypes [ i ] , tb . ElementTypes [ i ] ) ;
if ( merged = = null )
return null ;
mergedElements . Add ( merged ) ;
@ -1061,7 +1070,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1061,7 +1070,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
var mergedArgs = new IType [ pa . TypeArguments . Count ] ;
for ( int i = 0 ; i < pa . TypeArguments . Count ; i + + )
{
var merged = MergeTupleNam es ( pa . TypeArguments [ i ] , pb . TypeArguments [ i ] ) ;
var merged = MergeSimilarTyp es ( pa . TypeArguments [ i ] , pb . TypeArguments [ i ] ) ;
if ( merged = = null )
return null ;
mergedArgs [ i ] = merged ;
@ -1070,7 +1079,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1070,7 +1079,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
if ( a is ArrayType arrA & & b is ArrayType arrB & & arrA . Dimensions = = arrB . Dimensions )
{
var mergedElem = MergeTupleNam es ( arrA . ElementType , arrB . ElementType ) ;
var mergedElem = MergeSimilarTyp es ( arrA . ElementType , arrB . ElementType ) ;
if ( mergedElem = = null )
return null ;
return new ArrayType ( arrA . Compilation , mergedElem , arrA . Dimensions , arrA . Nullability ) ;
@ -1080,7 +1089,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1080,7 +1089,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// <summary>
/// Collapses bounds that are equal modulo tuple element names (possibly nested) into a
/// single merged type via <see cref="MergeTupleNam es"/>, across both bound sets. Bounds
/// single merged type via <see cref="MergeSimilarTyp es"/>, across both bound sets. Bounds
/// without a shape-equivalent partner are returned as-is.
/// </summary>
static ( IReadOnlyList < IType > LowerBounds , IReadOnlyList < IType > UpperBounds ) MergeShapeEquivalentBounds (
@ -1095,7 +1104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1095,7 +1104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool absorbed = false ;
for ( int i = 0 ; i < mergedBounds . Count & & ! absorbed ; i + + )
{
IType merged = MergeTupleNam es ( mergedBounds [ i ] , bound ) ;
IType merged = MergeSimilarTyp es ( mergedBounds [ i ] , bound ) ;
if ( merged ! = null )
{
// Bounds that are already equal merge to the existing entry itself;
@ -1120,7 +1129,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
@@ -1120,7 +1129,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
static IType [ ] MapToMergedBounds ( IEnumerable < IType > bounds , List < IType > mergedBounds )
{
return bounds . Select ( b = > mergedBounds . First ( m = > MergeTupleNam es ( m , b ) ! = null ) ) . Distinct ( ) . ToArray ( ) ;
return bounds . Select ( b = > mergedBounds . First ( m = > MergeSimilarTyp es ( m , b ) ! = null ) ) . Distinct ( ) . ToArray ( ) ;
}
#endregion