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
Assert.That(c.Method.FullName, Is.EqualTo("System.DateTimeOffset.op_Implicit")); Assert.That(c.Method.FullName, Is.EqualTo("System.DateTimeOffset.op_Implicit"));
Assert.That(ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)), Is.EqualTo(C.None)); 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] [Test]

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

@ -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> { } public class ClassWithAttributeOnTypeParameter<[Double(2)] T> { }
[Guid("790C6E0B-9194-4cc9-9426-A48A63185696"), InterfaceType(ComInterfaceType.InterfaceIsDual)] [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
/// </summary> /// </summary>
bool IsEncompassedBy(IType a, IType b) 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) bool IsEncompassingOrEncompassedBy(IType a, IType b)
{ {
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface return (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
&& (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
} }
IType FindMostEncompassedType(IEnumerable<IType> candidates) IType FindMostEncompassedType(IEnumerable<IType> candidates)
@ -1027,6 +1026,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType) Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{ {
// C# 4.0 spec §6.4.4 User-defined implicit conversions // 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); var operators = GetApplicableConversionOperators(fromResult, fromType, toType, false);
if (operators.Count > 0) if (operators.Count > 0)
@ -1069,6 +1075,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType) Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{ {
// C# 4.0 spec §6.4.5 User-defined explicit conversions // 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); var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
if (operators.Count > 0) if (operators.Count > 0)
{ {

Loading…
Cancel
Save