diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.cs b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.cs index 146cba9fb4..991d9c7934 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.cs @@ -66,6 +66,13 @@ public void TestRefTypeNewobj() MyClass value = new MyClass(); Console.WriteLine(value); } + + public void TestUnresolvedStructMemberCalls() + { + MyEnumerator val = default; + val.MoveNext(); + ((IDisposable)val/*cast due to constrained. prefix*/).Dispose(); + } } public class Issue3729_DerivedFromUnknown : MissingBase { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.il b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.il index f468655e6e..8ed0374995 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3729.il @@ -177,6 +177,23 @@ IL_000c: ret } + .method public hidebysig + instance void TestUnresolvedStructMemberCalls () cil managed + { + .maxstack 1 + .locals init ( + [0] valuetype [Library1]Library1.MyEnumerator + ) + + IL_0000: ldloca.s 0 + IL_0002: call instance bool [Library1]Library1.MyEnumerator::MoveNext() + IL_0007: pop + IL_0008: ldloca.s 0 + IL_000a: constrained. [Library1]Library1.MyEnumerator + IL_0010: callvirt instance void [System.Runtime]System.IDisposable::Dispose() + IL_0015: ret + } + .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 92aa24f1fc..58546162b3 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -2923,7 +2923,18 @@ internal TranslatedExpression TranslateTarget(ILInstruction? target, bool nonVir else { IType targetTypeHint = constrainedTo ?? memberDeclaringType; - if (CallInstruction.ExpectedTypeForThisPointer(memberDeclaringType, constrainedTo) == StackType.Ref) + if (target is Conv { + Kind: ConversionKind.Invalid, + InputType: StackType.Ref, + TargetType: IL.PrimitiveType.Unknown + } && targetTypeHint.Kind == TypeKind.Unknown) + { + target = target.UnwrapConv(ConversionKind.Invalid); + } + StackType expectedThisPointerType = CallInstruction.ExpectedTypeForThisPointer(memberDeclaringType, constrainedTo); + bool requiresManagedReference = expectedThisPointerType == StackType.Ref + || (expectedThisPointerType == StackType.Unknown && target.ResultType == StackType.Ref); + if (requiresManagedReference) { if (target.ResultType == StackType.Ref) { @@ -2935,13 +2946,15 @@ internal TranslatedExpression TranslateTarget(ILInstruction? target, bool nonVir } } var translatedTarget = Translate(target, targetTypeHint); - if (CallInstruction.ExpectedTypeForThisPointer(memberDeclaringType, constrainedTo) == StackType.Ref) + if (requiresManagedReference) { // When accessing members on value types, ensure we use a reference of the correct type, // and not a pointer or a reference to a different type (issue #1333) - if (!(translatedTarget.Type is ByReferenceType brt && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(brt.ElementType, constrainedTo ?? memberDeclaringType))) + IType expectedTargetType = constrainedTo ?? memberDeclaringType; + if (!(translatedTarget.Type is ByReferenceType brt + && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(brt.ElementType, expectedTargetType))) { - translatedTarget = translatedTarget.ConvertTo(new ByReferenceType(constrainedTo ?? memberDeclaringType), this); + translatedTarget = translatedTarget.ConvertTo(new ByReferenceType(expectedTargetType), this); } } if (translatedTarget.Expression is DirectionExpression)