Browse Source

Fix #3542: Invalid explicit cast for implicit conversion to generic struct with interface type constraint

pull/3550/head
Siegfried Pammer 3 months ago
parent
commit
b403b7bb3d
  1. 11
      ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs
  2. 13
      ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs
  3. 19
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

11
ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs

@ -529,6 +529,17 @@ namespace ICSharpCode.Decompiler.Tests.Semantics @@ -529,6 +529,17 @@ namespace ICSharpCode.Decompiler.Tests.Semantics
Assert.That(c.Method.FullName, Is.EqualTo("System.DateTimeOffset.op_Implicit"));
Assert.That(ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)), Is.EqualTo(C.None));
ITypeDefinition classImplementingIDisposable = compilation.FindType(typeof(ClassImplementingIDisposable)).GetDefinition();
ITypeDefinition genericStructWithIDisposableConstraintAndImplicitConversion = compilation.FindType(typeof(GenericStructWithIDisposableConstraintAndImplicitConversion<>)).GetDefinition();
IType genericStructIDisposableInstance = new ParameterizedType(genericStructWithIDisposableConstraintAndImplicitConversion, ImmutableArray.Create(compilation.FindType(typeof(IDisposable))));
// C => S<I>
Conversion c2 = conversions.ImplicitConversion(classImplementingIDisposable, genericStructIDisposableInstance);
Assert.That(c2.IsImplicit && c2.IsUserDefined);
Assert.That(c2.Method.FullName, Is.EqualTo("ICSharpCode.Decompiler.Tests.TypeSystem.GenericStructWithIDisposableConstraintAndImplicitConversion.op_Implicit"));
Assert.That(conversions.ImplicitConversion(genericStructIDisposableInstance, classImplementingIDisposable), Is.EqualTo(C.None));
}
[Test]

13
ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs

@ -559,6 +559,19 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -559,6 +559,19 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
}
}
public struct GenericStructWithIDisposableConstraintAndImplicitConversion<T> where T : IDisposable
{
public static implicit operator GenericStructWithIDisposableConstraintAndImplicitConversion<T>(T s)
{
return default(GenericStructWithIDisposableConstraintAndImplicitConversion<T>);
}
}
public class ClassImplementingIDisposable : IDisposable
{
public void Dispose() { }
}
public class ClassWithAttributeOnTypeParameter<[Double(2)] T> { }
[Guid("790C6E0B-9194-4cc9-9426-A48A63185696"), InterfaceType(ComInterfaceType.InterfaceIsDual)]

19
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -955,13 +955,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -955,13 +955,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
bool IsEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b).IsValid;
return StandardImplicitConversion(a, b).IsValid;
}
bool IsEncompassingOrEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
&& (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
return (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
}
IType FindMostEncompassedType(IEnumerable<IType> candidates)
@ -1027,6 +1026,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1027,6 +1026,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.4 User-defined implicit conversions
// user-defined conversions are not supported with interfaces
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
{
return Conversion.None;
}
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, false);
if (operators.Count > 0)
@ -1069,6 +1075,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1069,6 +1075,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined explicit conversions
// user-defined conversions are not supported with interfaces
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
{
return Conversion.None;
}
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
if (operators.Count > 0)
{

Loading…
Cancel
Save