Skip to content

Commit b403b7b

Browse files
Fix #3542: Invalid explicit cast for implicit conversion to generic struct with interface type constraint
1 parent d13835e commit b403b7b

File tree

3 files changed

+40
-3
lines changed

3 files changed

+40
-3
lines changed

ICSharpCode.Decompiler.Tests/Semantics/ConversionTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,17 @@ public void UserDefinedImplicitConversion()
529529
Assert.That(c.Method.FullName, Is.EqualTo("System.DateTimeOffset.op_Implicit"));
530530

531531
Assert.That(ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)), Is.EqualTo(C.None));
532+
533+
ITypeDefinition classImplementingIDisposable = compilation.FindType(typeof(ClassImplementingIDisposable)).GetDefinition();
534+
ITypeDefinition genericStructWithIDisposableConstraintAndImplicitConversion = compilation.FindType(typeof(GenericStructWithIDisposableConstraintAndImplicitConversion<>)).GetDefinition();
535+
IType genericStructIDisposableInstance = new ParameterizedType(genericStructWithIDisposableConstraintAndImplicitConversion, ImmutableArray.Create(compilation.FindType(typeof(IDisposable))));
536+
537+
// C => S<I>
538+
Conversion c2 = conversions.ImplicitConversion(classImplementingIDisposable, genericStructIDisposableInstance);
539+
Assert.That(c2.IsImplicit && c2.IsUserDefined);
540+
Assert.That(c2.Method.FullName, Is.EqualTo("ICSharpCode.Decompiler.Tests.TypeSystem.GenericStructWithIDisposableConstraintAndImplicitConversion.op_Implicit"));
541+
542+
Assert.That(conversions.ImplicitConversion(genericStructIDisposableInstance, classImplementingIDisposable), Is.EqualTo(C.None));
532543
}
533544

534545
[Test]

ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,19 @@ class Inner { }
559559
}
560560
}
561561

562+
public struct GenericStructWithIDisposableConstraintAndImplicitConversion<T> where T : IDisposable
563+
{
564+
public static implicit operator GenericStructWithIDisposableConstraintAndImplicitConversion<T>(T s)
565+
{
566+
return default(GenericStructWithIDisposableConstraintAndImplicitConversion<T>);
567+
}
568+
}
569+
570+
public class ClassImplementingIDisposable : IDisposable
571+
{
572+
public void Dispose() { }
573+
}
574+
562575
public class ClassWithAttributeOnTypeParameter<[Double(2)] T> { }
563576

564577
[Guid("790C6E0B-9194-4cc9-9426-A48A63185696"), InterfaceType(ComInterfaceType.InterfaceIsDual)]

ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -955,13 +955,12 @@ bool IsIntegerType(IType type)
955955
/// </summary>
956956
bool IsEncompassedBy(IType a, IType b)
957957
{
958-
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b).IsValid;
958+
return StandardImplicitConversion(a, b).IsValid;
959959
}
960960

961961
bool IsEncompassingOrEncompassedBy(IType a, IType b)
962962
{
963-
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
964-
&& (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
963+
return (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
965964
}
966965

967966
IType FindMostEncompassedType(IEnumerable<IType> candidates)
@@ -1027,6 +1026,13 @@ Conversion SelectOperator(IType mostSpecificSource, IType mostSpecificTarget, IL
10271026
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
10281027
{
10291028
// C# 4.0 spec §6.4.4 User-defined implicit conversions
1029+
1030+
// user-defined conversions are not supported with interfaces
1031+
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
1032+
{
1033+
return Conversion.None;
1034+
}
1035+
10301036
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, false);
10311037

10321038
if (operators.Count > 0)
@@ -1069,6 +1075,13 @@ Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromTyp
10691075
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
10701076
{
10711077
// C# 4.0 spec §6.4.5 User-defined explicit conversions
1078+
1079+
// user-defined conversions are not supported with interfaces
1080+
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
1081+
{
1082+
return Conversion.None;
1083+
}
1084+
10721085
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
10731086
if (operators.Count > 0)
10741087
{

0 commit comments

Comments
 (0)