Skip to content

Commit f54955a

Browse files
Merge pull request #3588 from icsharpcode/r502
Roslyn 5.0.0
2 parents d70a5e7 + 396b580 commit f54955a

File tree

15 files changed

+291
-52
lines changed

15 files changed

+291
-52
lines changed

Directory.Packages.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
<PackageVersion Include="K4os.Compression.LZ4" Version="1.3.8" />
1515
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
1616
<PackageVersion Include="McMaster.Extensions.Hosting.CommandLine" Version="4.1.1" />
17-
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
18-
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="4.14.0" />
17+
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
18+
<PackageVersion Include="Microsoft.CodeAnalysis.VisualBasic" Version="5.0.0" />
1919
<PackageVersion Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta2-22171-02" />
2020
<PackageVersion Include="Microsoft.DiaSymReader" Version="1.4.0" />
2121
<PackageVersion Include="Microsoft.DiaSymReader.Native" Version="17.0.0-beta1.21524.1" />

ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ internal static DecompilerSettings GetSettings(CompilerOptions cscOptions)
721721
CompilerOptions.UseRoslyn1_3_2 => CSharp.LanguageVersion.CSharp6,
722722
CompilerOptions.UseRoslyn2_10_0 => CSharp.LanguageVersion.CSharp7_3,
723723
CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0,
724-
_ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp13_0,
724+
_ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp14_0,
725725
};
726726
DecompilerSettings settings = new(langVersion) {
727727
// Never use file-scoped namespaces

ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ public async Task Issue3598([ValueSource(nameof(roslyn4OrNewerOptions))] Compile
562562
[Test]
563563
public async Task ExtensionProperties([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
564564
{
565-
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
565+
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview | CompilerOptions.NullableEnable);
566566
}
567567

568568
[Test]

ICSharpCode.Decompiler/CSharp/CallBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1457,7 +1457,7 @@ private ExpressionWithResolveResult HandleImplicitConversion(IMethod method, Tra
14571457
var conversions = CSharpConversions.Get(expressionBuilder.compilation);
14581458
IType targetType = method.ReturnType;
14591459
var conv = conversions.ImplicitConversion(argument.Type, targetType);
1460-
if (!(conv.IsUserDefined && conv.IsValid && conv.Method.Equals(method)))
1460+
if (!(conv.IsUserDefined && conv.IsValid && conv.Method.Equals(method, NormalizeTypeVisitor.TypeErasure)))
14611461
{
14621462
// implicit conversion to targetType isn't directly possible, so first insert a cast to the argument type
14631463
argument = argument.ConvertTo(method.Parameters[0].Type, expressionBuilder);

ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

Lines changed: 159 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ Conversion StandardImplicitConversion(IType fromType, IType toType, bool allowTu
247247
if (IdentityConversion(elementType, spanElementType))
248248
return Conversion.InlineArrayConversion;
249249
}
250+
if (IsImplicitSpanConversion(fromType, toType))
251+
{
252+
return Conversion.ImplicitSpanConversion;
253+
}
250254
return Conversion.None;
251255
}
252256

@@ -1229,6 +1233,49 @@ List<OperatorInfo> GetApplicableConversionOperators(ResolveResult fromResult, IT
12291233
}
12301234
#endregion
12311235

1236+
#region Implicit Span Conversion
1237+
1238+
bool IsImplicitSpanConversion(IType fromType, IType toType)
1239+
{
1240+
if (!compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes))
1241+
{
1242+
return false;
1243+
}
1244+
1245+
// An implicit span conversion permits array_types, System.Span<T>, System.ReadOnlySpan<T>,
1246+
// and string to be converted between each other
1247+
// see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-14.0/first-class-span-types#span-conversions
1248+
1249+
switch (fromType)
1250+
{
1251+
case ArrayType { Dimensions: 1, ElementType: var elementType }:
1252+
if (toType.IsKnownType(KnownTypeCode.SpanOfT))
1253+
{
1254+
return IdentityConversion(elementType, toType.TypeArguments[0]);
1255+
}
1256+
if (toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1257+
{
1258+
return IdentityConversion(elementType, toType.TypeArguments[0])
1259+
|| IsImplicitReferenceConversion(elementType, toType.TypeArguments[0]);
1260+
}
1261+
break;
1262+
case ParameterizedType pt when pt.IsKnownType(KnownTypeCode.SpanOfT) || pt.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
1263+
if (toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1264+
{
1265+
return IdentityConversion(pt.TypeArguments[0], toType.TypeArguments[0])
1266+
|| IsImplicitReferenceConversion(pt.TypeArguments[0], toType.TypeArguments[0]);
1267+
}
1268+
break;
1269+
case var s when s.IsKnownType(KnownTypeCode.String):
1270+
return toType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT)
1271+
&& toType.TypeArguments[0].IsKnownType(KnownTypeCode.Char);
1272+
}
1273+
1274+
return false;
1275+
}
1276+
1277+
#endregion
1278+
12321279
#region AnonymousFunctionConversion
12331280
Conversion AnonymousFunctionConversion(ResolveResult resolveResult, IType toType)
12341281
{
@@ -1487,11 +1534,32 @@ Conversion TupleConversion(IType fromType, IType toType, bool isExplicit)
14871534

14881535
#region BetterConversion
14891536
/// <summary>
1490-
/// Gets the better conversion (C# 4.0 spec, §7.5.3.3)
1537+
/// Gets the better conversion (from expression) (C# 8.0 spec, §12.6.4.5)
14911538
/// </summary>
14921539
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
14931540
public int BetterConversion(ResolveResult resolveResult, IType t1, IType t2)
14941541
{
1542+
bool t1Exact = IsExactlyMatching(resolveResult, t1);
1543+
bool t2Exact = IsExactlyMatching(resolveResult, t2);
1544+
if (t1Exact && !t2Exact)
1545+
return 1;
1546+
if (t2Exact && !t1Exact)
1547+
return 2;
1548+
if (!t1Exact && !t2Exact)
1549+
{
1550+
bool c1ImplicitSpanConversion = IsImplicitSpanConversion(resolveResult.Type, t1);
1551+
bool c2ImplicitSpanConversion = IsImplicitSpanConversion(resolveResult.Type, t2);
1552+
if (c1ImplicitSpanConversion && !c2ImplicitSpanConversion)
1553+
return 1;
1554+
if (c2ImplicitSpanConversion && !c1ImplicitSpanConversion)
1555+
return 2;
1556+
}
1557+
if (t1Exact == t2Exact)
1558+
{
1559+
int r = BetterConversionTarget(t1, t2);
1560+
if (r != 0)
1561+
return r;
1562+
}
14951563
LambdaResolveResult lambda = resolveResult as LambdaResolveResult;
14961564
if (lambda != null)
14971565
{
@@ -1542,20 +1610,56 @@ public int BetterConversion(ResolveResult resolveResult, IType t1, IType t2)
15421610
}
15431611

15441612
/// <summary>
1545-
/// Unpacks the generic Task[T]. Returns null if the input is not Task[T].
1613+
/// Gets whether an expression E exactly matches a type T (C# 8.0 spec, §12.6.4.6)
15461614
/// </summary>
1547-
static IType UnpackTask(IType type)
1615+
bool IsExactlyMatching(ResolveResult e, IType t)
15481616
{
1549-
ParameterizedType pt = type as ParameterizedType;
1550-
if (pt != null && pt.TypeParameterCount == 1 && pt.Name == "Task" && pt.Namespace == "System.Threading.Tasks")
1617+
var s = e.Type;
1618+
if (IdentityConversion(s, t))
1619+
return true;
1620+
if (e is LambdaResolveResult lambda)
15511621
{
1552-
return pt.GetTypeArgument(0);
1622+
if (!lambda.IsAnonymousMethod)
1623+
{
1624+
t = UnpackExpressionTreeType(t);
1625+
}
1626+
IMethod m = t.GetDelegateInvokeMethod();
1627+
if (m == null)
1628+
return false;
1629+
IType[] parameterTypes = new IType[m.Parameters.Count];
1630+
for (int i = 0; i < parameterTypes.Length; i++)
1631+
parameterTypes[i] = m.Parameters[i].Type;
1632+
var x = lambda.GetInferredReturnType(parameterTypes);
1633+
var y = m.ReturnType;
1634+
if (IdentityConversion(x, y))
1635+
return true;
1636+
if (lambda.IsAsync)
1637+
{
1638+
x = UnpackTask(x);
1639+
y = UnpackTask(y);
1640+
}
1641+
if (x != null && y != null)
1642+
return IsExactlyMatching(new ResolveResult(x), y);
1643+
return false;
1644+
}
1645+
else
1646+
{
1647+
return false;
15531648
}
1554-
return null;
15551649
}
15561650

15571651
/// <summary>
1558-
/// Gets the better conversion (C# 4.0 spec, §7.5.3.4)
1652+
/// Unpacks the generic TaskType[T]. Returns null if the input is not TaskType[T].
1653+
/// </summary>
1654+
static IType UnpackTask(IType type)
1655+
{
1656+
return (TaskType.IsTask(type) || TaskType.IsCustomTask(type, out _)) && type.TypeParameterCount == 1
1657+
? type.TypeArguments[0]
1658+
: null;
1659+
}
1660+
1661+
/// <summary>
1662+
/// Gets the better conversion (from type) (C# 4.0 spec, §7.5.3.4)
15591663
/// </summary>
15601664
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
15611665
public int BetterConversion(IType s, IType t1, IType t2)
@@ -1570,17 +1674,57 @@ public int BetterConversion(IType s, IType t1, IType t2)
15701674
}
15711675

15721676
/// <summary>
1573-
/// Gets the better conversion target (C# 4.0 spec, §7.5.3.5)
1677+
/// Gets the better conversion target (C# 9.0 spec, §12.6.4.7)
15741678
/// </summary>
15751679
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
15761680
int BetterConversionTarget(IType t1, IType t2)
15771681
{
1578-
bool t1To2 = ImplicitConversion(t1, t2).IsValid;
1579-
bool t2To1 = ImplicitConversion(t2, t1).IsValid;
1580-
if (t1To2 && !t2To1)
1581-
return 1;
1582-
if (t2To1 && !t1To2)
1583-
return 2;
1682+
if (t1.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1683+
{
1684+
if (t2.IsKnownType(KnownTypeCode.SpanOfT))
1685+
{
1686+
if (IdentityConversion(t1.TypeArguments[0], t2.TypeArguments[0]))
1687+
return 1;
1688+
}
1689+
if (t2.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1690+
{
1691+
bool t1To2 = ImplicitConversion(t1.TypeArguments[0], t2.TypeArguments[0]).IsValid;
1692+
bool t2To1 = ImplicitConversion(t2.TypeArguments[0], t1.TypeArguments[0]).IsValid;
1693+
if (t1To2 && !t2To1)
1694+
return 1;
1695+
}
1696+
}
1697+
1698+
if (t2.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1699+
{
1700+
if (t1.IsKnownType(KnownTypeCode.SpanOfT))
1701+
{
1702+
if (IdentityConversion(t2.TypeArguments[0], t1.TypeArguments[0]))
1703+
return 2;
1704+
}
1705+
if (t1.IsKnownType(KnownTypeCode.ReadOnlySpanOfT))
1706+
{
1707+
bool t1To2 = ImplicitConversion(t1.TypeArguments[0], t2.TypeArguments[0]).IsValid;
1708+
bool t2To1 = ImplicitConversion(t2.TypeArguments[0], t1.TypeArguments[0]).IsValid;
1709+
if (t2To1 && !t1To2)
1710+
return 2;
1711+
}
1712+
}
1713+
1714+
{
1715+
bool t1To2 = ImplicitConversion(t1, t2).IsValid;
1716+
bool t2To1 = ImplicitConversion(t2, t1).IsValid;
1717+
if (t1To2 && !t2To1)
1718+
return 1;
1719+
if (t2To1 && !t1To2)
1720+
return 2;
1721+
}
1722+
1723+
var s1 = UnpackTask(t1);
1724+
var s2 = UnpackTask(t2);
1725+
if (s1 != null && s2 != null)
1726+
return BetterConversionTarget(s1, s2);
1727+
15841728
TypeCode t1Code = ReflectionHelper.GetTypeCode(t1);
15851729
TypeCode t2Code = ReflectionHelper.GetTypeCode(t2);
15861730
if (IsBetterIntegralType(t1Code, t2Code))

ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2171,7 +2171,7 @@ static bool IsEligibleExtensionMethod(ICompilation compilation, CSharpConversion
21712171
thisParameterType = thisParameterType.AcceptVisitor(substitution);
21722172
}
21732173
Conversion c = conversions.ImplicitConversion(targetType, thisParameterType);
2174-
return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion);
2174+
return c.IsValid && (c.IsIdentityConversion || c.IsReferenceConversion || c.IsBoxingConversion || c.IsImplicitSpanConversion);
21752175
}
21762176

21772177
/// <summary>

ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,8 @@ void CheckApplicability(Candidate candidate)
710710
candidate.ArgumentConversions[i] = c;
711711
if (IsExtensionMethodInvocation && parameterIndex == 0)
712712
{
713-
// First parameter to extension method must be an identity, reference or boxing conversion
714-
if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
713+
// First parameter to extension method must be an identity, reference, boxing or span conversion
714+
if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion || c == Conversion.ImplicitSpanConversion))
715715
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
716716
}
717717
else

ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -659,17 +659,31 @@ void MakeExactInference(IType U, IType V)
659659
return;
660660
}
661661
// Handle array types:
662-
ArrayType arrU = U as ArrayType;
663-
ArrayType arrV = V as ArrayType;
664-
if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions)
662+
U = U.TupleUnderlyingTypeOrSelf();
663+
V = V.TupleUnderlyingTypeOrSelf();
664+
switch ((U, V))
665665
{
666-
MakeExactInference(arrU.ElementType, arrV.ElementType);
667-
return;
666+
case (ArrayType arrU, ArrayType arrV) when arrU.Dimensions == arrV.Dimensions:
667+
MakeExactInference(arrU.ElementType, arrV.ElementType);
668+
return;
669+
case (ArrayType arrU, ParameterizedType spanV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanV.IsKnownType(KnownTypeCode.SpanOfT):
670+
MakeExactInference(arrU.ElementType, spanV.TypeArguments[0]);
671+
return;
672+
case (ParameterizedType spanU, ParameterizedType spanV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanU.IsKnownType(KnownTypeCode.SpanOfT) && spanV.IsKnownType(KnownTypeCode.SpanOfT):
673+
MakeExactInference(spanU.TypeArguments[0], spanV.TypeArguments[0]);
674+
return;
675+
case (ArrayType arrU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
676+
MakeExactInference(arrU.ElementType, rosV.TypeArguments[0]);
677+
return;
678+
case (ParameterizedType spanU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanU.IsKnownType(KnownTypeCode.SpanOfT) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
679+
MakeExactInference(spanU.TypeArguments[0], rosV.TypeArguments[0]);
680+
return;
681+
case (ParameterizedType rosU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && rosU.IsKnownType(KnownTypeCode.ReadOnlySpanOfT) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
682+
MakeExactInference(rosU.TypeArguments[0], rosV.TypeArguments[0]);
683+
return;
668684
}
669685
// Handle parameterized type:
670-
ParameterizedType pU = U.TupleUnderlyingTypeOrSelf() as ParameterizedType;
671-
ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType;
672-
if (pU != null && pV != null
686+
if (U is ParameterizedType pU && V is ParameterizedType pV
673687
&& object.Equals(pU.GenericType, pV.GenericType)
674688
&& pU.TypeParameterCount == pV.TypeParameterCount)
675689
{
@@ -751,21 +765,33 @@ void MakeLowerBoundInference(IType U, IType V)
751765
return;
752766
}
753767
// Handle array types:
754-
ArrayType arrU = U as ArrayType;
755-
ArrayType arrV = V as ArrayType;
756-
ParameterizedType pV = V.TupleUnderlyingTypeOrSelf() as ParameterizedType;
757-
if (arrU != null && arrV != null && arrU.Dimensions == arrV.Dimensions)
768+
V = V.TupleUnderlyingTypeOrSelf();
769+
switch ((U, V))
758770
{
759-
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
760-
return;
761-
}
762-
else if (arrU != null && pV.IsArrayInterfaceType() && arrU.Dimensions == 1)
763-
{
764-
MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0));
765-
return;
771+
case (ArrayType arrU, ArrayType arrV) when arrU.Dimensions == arrV.Dimensions:
772+
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
773+
return;
774+
case (ArrayType arrU, ParameterizedType spanV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanV.IsKnownType(KnownTypeCode.SpanOfT):
775+
MakeLowerBoundInference(arrU.ElementType, spanV.TypeArguments[0]);
776+
return;
777+
case (ParameterizedType spanU, ParameterizedType spanV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanU.IsKnownType(KnownTypeCode.SpanOfT) && spanV.IsKnownType(KnownTypeCode.SpanOfT):
778+
MakeLowerBoundInference(spanU.TypeArguments[0], spanV.TypeArguments[0]);
779+
return;
780+
case (ArrayType arrU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
781+
MakeLowerBoundInference(arrU.ElementType, rosV.TypeArguments[0]);
782+
return;
783+
case (ParameterizedType spanU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && spanU.IsKnownType(KnownTypeCode.SpanOfT) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
784+
MakeLowerBoundInference(spanU.TypeArguments[0], rosV.TypeArguments[0]);
785+
return;
786+
case (ParameterizedType rosU, ParameterizedType rosV) when compilation.TypeSystemOptions.HasFlag(TypeSystemOptions.FirstClassSpanTypes) && rosU.IsKnownType(KnownTypeCode.ReadOnlySpanOfT) && rosV.IsKnownType(KnownTypeCode.ReadOnlySpanOfT):
787+
MakeLowerBoundInference(rosU.TypeArguments[0], rosV.TypeArguments[0]);
788+
return;
789+
case (ArrayType arrU, ParameterizedType arrIntfV) when arrIntfV.IsArrayInterfaceType() && arrU.Dimensions == 1:
790+
MakeLowerBoundInference(arrU.ElementType, arrIntfV.TypeArguments[0]);
791+
return;
766792
}
767793
// Handle parameterized types:
768-
if (pV != null)
794+
if (V is ParameterizedType pV)
769795
{
770796
ParameterizedType uniqueBaseType = null;
771797
foreach (IType baseU in U.GetAllBaseTypes())

0 commit comments

Comments
 (0)