Browse Source

#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.
pull/1612/head
Daniel Grunwald 6 years ago
parent
commit
c366235246
  1. 6
      ICSharpCode.Decompiler/IL/ILReader.cs
  2. 4
      ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs
  3. 8
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

6
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1187,14 +1187,14 @@ namespace ICSharpCode.Decompiler.IL @@ -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();
}

4
ICSharpCode.Decompiler/IL/Instructions/LdFlda.cs

@ -36,7 +36,9 @@ namespace ICSharpCode.Decompiler.IL @@ -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;
}
}

8
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -477,7 +477,9 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -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<IParameter>();
for (int i = 0; i < signature.RequiredParameterCount; i++) {
@ -553,6 +555,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -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,

Loading…
Cancel
Save