From c366235246d8157e005ce694ff80f03eb519bd96 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 25 Jul 2019 22:47:14 +0200 Subject: [PATCH] #1349: Fix type substitution for members of unknown generic types (due to unresolved references) Also, assume that unknown inputs to ldfld are temporaries, not unmanaged pointers. This avoids emitting weird pointer casts when accessing fields on unresolved value types. --- ICSharpCode.Decompiler/IL/ILReader.cs | 6 +++--- ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs | 4 +++- ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs | 8 +++++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 552f2468d..49ce05219 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -1187,14 +1187,14 @@ namespace ICSharpCode.Decompiler.IL return Pop(StackType.O); case false: // field of value type: ldfld can handle temporaries - if (PeekStackType() == StackType.O) + if (PeekStackType() == StackType.O || PeekStackType() == StackType.Unknown) return new AddressOf(Pop()); else return PopPointer(); default: // field in unresolved type - if (PeekStackType() == StackType.O) - return Pop(StackType.O); + if (PeekStackType() == StackType.O || PeekStackType() == StackType.Unknown) + return Pop(); else return PopPointer(); } diff --git a/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs b/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs index 87917b8d4..6fdd3e382 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs @@ -36,7 +36,9 @@ namespace ICSharpCode.Decompiler.IL break; case null: // field of unresolved type - Debug.Assert(target.ResultType == StackType.O || target.ResultType == StackType.I || target.ResultType == StackType.Ref); + Debug.Assert(target.ResultType == StackType.O || target.ResultType == StackType.I + || target.ResultType == StackType.Ref || target.ResultType == StackType.Unknown, + "Field of unresolved type with invalid target"); break; } } diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs index 110a4802d..1fb75d51d 100644 --- a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs +++ b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs @@ -477,7 +477,9 @@ namespace ICSharpCode.Decompiler.TypeSystem typeParameters.Add(new DefaultTypeParameter(m, i)); } m.TypeParameters = typeParameters; - substitution = new TypeParameterSubstitution(null, typeParameters); + substitution = new TypeParameterSubstitution(declaringType.TypeArguments, typeParameters); + } else if (declaringType.TypeArguments.Count > 0) { + substitution = declaringType.GetSubstitution(); } var parameters = new List(); for (int i = 0; i < signature.RequiredParameterCount; i++) { @@ -553,6 +555,10 @@ namespace ICSharpCode.Decompiler.TypeSystem var field = declaringType.GetFields(f => f.Name == name && CompareTypes(f.ReturnType, signature), GetMemberOptions.IgnoreInheritedMembers).FirstOrDefault(); if (field == null) { + // If it's a field in a generic type, we need to substitute the type arguments: + if (declaringType.TypeArguments.Count > 0) { + signature = signature.AcceptVisitor(declaringType.GetSubstitution()); + } field = new FakeField(Compilation) { ReturnType = signature, Name = name,